이전 결측치 처리 포스팅에서 결측치를 살펴보는데 중점을 뒀다면, 이번에는 조금 더 난이도도 올리고 현실적인 내용을 다루고자 한다.
데이터 준비
R의 내장 데이터인 “airquality”를 사용한다.
1 | df = airquality |
결측치 파악
전에는 각 column별로 결측치를 알아봤지만, row별로 알아보는 것은 어떻게 할까? 이전처럼 apply()
함수를 사용하되, MARGIN
인자만 조정해주면 되겠다.
1 | row_na_cnt = apply(X = df, MARGIN = 1, FUN = function(x){sum(is.na(x))}) |
“row_na_cnt” 객체에 저장된 것은 각 row의 결측치 개수이다. 그리고 이를 요약해본다면 table()
함수를 사용할 수 있다. 이 작업은 특정 row에 결측값이 너무 많을 경우 모델링 이전에 제거할 필요가 있는데, 이 때 사용하면 좋다.
결측치 처리
이전 포스팅에서 다뤘던 결측치 처리는 객체에서 결측치인 원소 또는 결측치가 포함된 row를 제거하는 방식이었다. 이번에는 결측치 제거 대신 값을 채워넣는 방법을 알아보자.
기본 함수 활용
1 | head(df, 2) # 1 |
우선 1번 코드로 데이터를 확인하고 다음 코드를 작성하자. 언제나 머릿속에 다루고 있는 데이터를 외워 넣어야 하지만 그렇지 못하면 이렇게 head()
함수를 많이 적어줘야 하겠다.
2번 코드는 is.na(df$Ozone)
으로 row 범위를 지정해주고, 쉼표 뒤에 “Ozone”을 명시하여 “Ozone” 변수의 결측값을 -999로 치환하는 코드가 되겠다. 데이터프레임의 특정 변수의 결측치 처리를 할 때 이 코드 형식을 기본으로 사용하게 되는데 특히 변수명을 선언하지 않으면 결측치가 있는 row의 전체 column에 대하여 값 치환이 되기 때문에 주의해야 한다. 별거 아니라고 할 수 있지만, 꽤 빈번하게 발생하는 실수이다.
5번 코드 수행 전에 산술함수의 na.rm
인자의 기능을 알아보기 위해 3번과 4번 코드를 잘 보도록 하자. 산술연산을 수행하고자 하는 1차원 벡터에 결측치가 있다면 3번 코드처럼 결과도 결측으로 나온다. 이렇게 결측이 있는 경우는 4번 코드와 같이 na.rm
인자에 TRUE
를 할당해줘야 결측치를 제외한 나머지 값으로 연산한 결과를 반환한다. 이제 2~4번 코드를 살펴본 지식을 종합해보면 5번 코드의 해석은 충분히 할 수 있을 것이다.
zoo 패키지 활용
결측치 처리에 사용하는 대표적인 패키지 zoo 를 소개하고자 한다.
1 | library("zoo") |
1번 코드는 선행 보간(forward fill)으로 결측치가 존재할 경우 최초 결측치 직전의 값을 끌어와서 메꾸는 방식이다.
2번 코드는 후행 보간(backward fill)으로 결측치가 존재할 경우 최후 결측치 직후의 값을 끌어와서 메꾸는 방식이다.
zoo 패키지는 시계열 데이터를 다루는 함수가 많지만, 결측치를 처리하는 함수도 여러개 있다. 그 중에서 na.locf0()
함수가 기본 함수 하나로 커버하지 못하는 결과를 산출하기에 여기서 소개한 것인데, 이 함수의 활용은 엑셀 전처리편에서 소개하고 있으니 관심있으면 확인해보길 바란다.
마치며
여기까지 읽었다면 데이터 분석에서 발생하는 대부분의 결측치를 처리할 수 있을 것이다. 다만, 시계열 데이터나 공간 데이터의 결측 부분은 또 다른 영역인데 이를 해결하는데 필요한 지식의 영역은 보간(interpolation)이다. 이와 관련해서 선형 보간, 공간 보간 등 다양한 방법이 있는데 향후 포스팅을 통해 알아보도록 하겠다.
<결측치 처리 시리즈>
R 결측치 처리 - 1
R 결측치 처리 - 2