18 결측값
18.1 들어가기
Missing topics:
Missing values generated from matching data frames (i.e.
left_join()
andanti_join()
Last observation carried forward and
tidy::fill()
coalesce()
andna_if()
18.2 기초
18.2.1 결측값
R 에서 비교를 까다롭게 만드는 중요한 기능은 결측값, 즉 NA
(“not availables”, 해당없음) 이다.
NA
는 알려지지 않은 값을 표시하므로 결측값은 “파급된다”: 즉 알려지지 않은 값이 포함된 모든 연산 결과는 역시 알려지지 않을 것이다.
NA > 5
#> [1] NA
10 == NA
#> [1] NA
NA + 10
#> [1] NA
NA / 2
#> [1] NA
가장 헷갈리는 결과는 다음이다:
NA == NA
#> [1] NA
문맥이 조금 더 있으면 왜 이것이 참인지 이해하기가 쉽다:
# Let x be Mary's age. We don't know how old she is.
x <- NA
# Let y be John's age. We don't know how old he is.
y <- NA
# Are John and Mary the same age?
x == y
#> [1] NA
# We don't know!
어떤 값이 결측인지 확인하고 싶다면 is.na()
를 사용하라:
is.na(x)
#> [1] TRUE
18.2.2 Exercises
How many flights have a missing
dep_time
? What other variables are missing? What might these rows represent?How could you use
arrange()
to sort all missing values to the start? (Hint: use!is.na()
).Come up with another approach that will give you the same output as
not_cancelled %>% count(dest)
andnot_cancelled %>% count(tailnum, wt = distance)
(without usingcount()
).Look at the number of cancelled flights per day. Is there a pattern? Is the proportion of cancelled flights related to the average delay?
18.3 명시적 vs 암묵적 결측값
데이터셋의 표현 방식을 변경하면 결측값에 중요하고도 미묘한 이슈가 나타난다. 놀랍게도 데이터값은 다음 두 가지 방식으로 결측될 수 있다.
-
명시적 으로 즉,
NA
로 표시됨. - 암묵적 으로, 즉 단순히 데이터에 존재하지 않음.
아주 간단한 데이터셋으로 이를 설명해보자.
stocks <- tibble(
year = c(2015, 2015, 2015, 2015, 2016, 2016, 2016),
qtr = c( 1, 2, 3, 4, 2, 3, 4),
return = c(1.88, 0.59, 0.35, NA, 0.92, 0.17, 2.66)
)
이 데이터셋에는 결측값이 다음과 같이 두 개가 존재한다.
2015 년 4 분기 수익은 명백하게 결측되어 있다. 그 값이 있어야 할 셀에
NA
가 대신 있기 때문이다.2016 년 1 분기 수익은 암묵적으로 결측되었다. 수익이 데이터셋에 없기 때문이다.
다음의 선문답으로 둘의 차이를 생각해볼 수 있다. 명시적 결측값은 결측의 존재이다. 암묵적 결측값은 존재의 결측이다.
데이터셋 표현법으로 암묵적 값을 명시적으로 만들 수 있다. 예를 들어 연도를 열로 넣어 암묵적 결측값을 명시적으로 만들 수 있다.
stocks %>%
pivot_wider(names_from = year, values_from = return)
#> # A tibble: 4 × 3
#> qtr `2015` `2016`
#> <dbl> <dbl> <dbl>
#> 1 1 1.88 NA
#> 2 2 0.59 0.92
#> 3 3 0.35 0.17
#> 4 4 NA 2.66
이러한 명시적인 결측값은 어떤 데이터 표현에서는 중요하지 않을 수 있으므로 pivot_longer()
에서 values_drop_na = TRUE
를 설정하여 명시적 결측값을 암묵적으로 전환할 수 있다.
stocks %>%
pivot_wider(names_from = year, values_from = return) %>%
pivot_longer(
cols = c(`2015`, `2016`),
names_to = "year",
values_to = "return",
values_drop_na = TRUE
)
#> # A tibble: 6 × 3
#> qtr year return
#> <dbl> <chr> <dbl>
#> 1 1 2015 1.88
#> 2 2 2015 0.59
#> 3 2 2016 0.92
#> 4 3 2015 0.35
#> 5 3 2016 0.17
#> 6 4 2016 2.66
타이디 데이터에서 결측값을 명시적으로 표현하는 또 다른 중요한 도구로 complete()
가 있다.
stocks %>%
complete(year, qtr)
#> # A tibble: 8 × 3
#> year qtr return
#> <dbl> <dbl> <dbl>
#> 1 2015 1 1.88
#> 2 2015 2 0.59
#> 3 2015 3 0.35
#> 4 2015 4 NA
#> 5 2016 1 NA
#> 6 2016 2 0.92
#> # … with 2 more rows
complete()
는 열 집합을 인풋으로, 고유한 조합을 모두 찾는다. 그런 다음 원본 데이터셋에 모든 값이 포함되도록, 필요한 곳에 명시적 NA
를 채운다.
결측값 작업할 때 알아야 할 중요한 도구가 하나 더 있다. 데이터 소스가 주로 데이터 입력에 사용된 경우 결측값은 이전 값이 전달되어야 함을 나타낸다.
treatment <- tribble(
~person, ~treatment, ~response,
"Derrick Whitmore", 1, 7,
NA, 2, 10,
NA, 3, 9,
"Katherine Burke", 1, 4
)
이러한 결측값을 fill()
을 사용하여 채울 수 있다.
이 함수는 결측값을 가장 최근의 비결측값으로 치환하고자 하는 열(집합)을 취한다. 이를 마지막 관측값 이월이라고도 한다.
treatment %>%
fill(person)
#> # A tibble: 4 × 3
#> person treatment response
#> <chr> <dbl> <dbl>
#> 1 Derrick Whitmore 1 7
#> 2 Derrick Whitmore 2 10
#> 3 Derrick Whitmore 3 9
#> 4 Katherine Burke 1 4
18.3.1 연습문제
pivot_wider()
와complete()
의fill
인수를 비교 대조하라.fill()
의direction
인수는 무엇을 하는가?