안녕하세요 밥한그릇입니다.
오늘은 R언어에서 데이터 분석을 할 때, 결측치와 이상치를 처리하는 간단한 방법들에 대해 알아볼거에요.
이 과정은 데이터 전처리 중, 데이터 정제 과정에 속합니다.
결측치는 데이터 분석 시 값을 처리할 수 없어 필수적으로 처리해야하고요. 극단치(=특이치, 이상치)는 데이터의 분포 및 평균을 왜곡하는 경우가 많아 이것도 처리하는 게 좋습니다.
극단치에 의한 통계 왜곡의 대표 사례로는, 미국의 노스캐롤라이나 대학의 졸업생 연봉(초봉)평균의 사례가 유명합니다.
졸업생들의 평균이 가장 높은 학과가 지리학과로 한화로 평균 1억이 넘는 연봉을 기록했는데요. 어떻게 지리학과에서 이렇게 많은 연봉을 받나 원인을 알아보니, 전설적인 농구선수 마이클 조던의 연봉 때문에 평균이 덩달아 저렇게 올라간 것이었습니다. (...)
그 선수의 연봉이 워낙 천문학적이다보니, 저렇게 평균값이 왜곡되어 나온 것이죠.
그럼 저 학과의 졸업생 연봉이 대체로 어떤 지 제대로 평균값을 구하려면 조던과 같은 특이치 연봉을 제외하고 졸업생 연봉 평균을 구해야겠죠? 그래서 극단치 제거가 데이터 분석에서 중요한 것이랍니다~
그럼 이제 예제코드와 결과를 보며 그 처리방법을 소개하도록 하겠습니다.
다음은 제가 과제 중 만든 ppt의 일부입니다.
결측치(= NA값)는 저렇게 is.na()로 확인합니다.
그다음 연속형 변수의 결측치는 boxplot으로 파악하고, 명목형 변수의 결측치는 barplot으로 확인하고 있죠.
결측치 처리
결측치 여부는 저렇게 table(is.na(data))로도 알 수 있지만, 좀 더 자세하게 어디에서 결측치가 나는 지 알기 위해서 다음과 같은 방법을 사용해도 좋습니다.
- 변수(열) 별로 몇 개의 결측치가 나오는 지 확인
colSums(is.na(df))
#varA varB varC varD varE varF
# 0 1 1 1 0 2
- 변수(열) 별로 결측치가 있는지 / 없는 지 확인
colSums(is.na(df)) == 0 # converts to logical TRUE/FALSE
#varA varB varC varD varE varF
#TRUE FALSE FALSE FALSE TRUE FALSE
극단치가 있다면 어떻게 처리하는가?
저는 다음과 같은 가장 간단한 방식을 주로 사용합니다.
- NA가 포함된 행을 제거
data <- na.omit(data)
# NA가 포함된 행을 전부 제거
- NA가 포함된 행의 값을 0으로 치환
data[is.na(data)] = 0
결측치를 0이 아닌 임의의 다른 값으로 채워주는 경우도 많다고 합니다. 참고하세요.
연속형 변수의 이상치(극단치) 처리
참고로, 이상치 = 극단치 = 특이값 입니다.
연속형(=수치형) 변수의 경우에는, boxplot을 출력하여 그 이상치를 처리할 수 있습니다.
boxplot에 대해서 더 자세히 알려면 다음의 링크를 클릭하여 살펴보고 옵시다.
https://bioinformaticsandme.tistory.com/245
[R] 상자그림(Box plot)
[R] 상자그림(Box plot) Start BioinformaticsAndMe 1. 상자그림(Box plot) : 상자그림은 특정한 수치 값을 기반으로 그려진, 자료 특성이 요약된 그래프 : 사분위수범위(Inter-Quartile Range;IQR) = Q1~Q3..
bioinformaticsandme.tistory.com
다음은 연속형의 이상치를 처리하는 예시 코드입니다.
하나의 변수만 예시로 처리해보겠습니다.
boxplot(data$변수명)$stats를 시행하면 boxplot 도표와 함께 오른쪽과 같이 5행을 가진 어떤 리스트가 나와요.
여기에서 주목해야할 부분은 첫번째 행과 5번째 행입니다.
0~12까지가 저기 boxplot의 수염선 범위이고요, 이 범위를 벗어나는 값들이 저기 boxplot에서 '하얀색 점'으로 표시된 이상치입니다.
그러니 극단치를 없애려면 저기 12보다 큰 값들을 없애면 된다는 거겠죠?
ifelse()를 통해 극단치 범위에 있는 값들을 NA로 치환해 준 뒤, NA가 포함된 행을 제거하면 극단치 처리가 끝납니다.
# 연속형 변수 극단치 파악 - box plot
boxplot(data$관공서.수)$stats # 극단치 O
# 극단치 제거
data$관공서.수 <- ifelse(data$관공서.수 > 12, NA, data$관공서.수) # 극단치 NA로 치환
data <- na.omit(data) # NA 포함된 행 제거
사실 저렇게 처리를 해줘도 boxplot을 출력했을 때 다시 하얀 점이 나타나기도 합니다. 이상치는 '상대적'이기 때문이죠. 이상치를 쳐내고 난 뒤의 값에서도 '상대적'으로 멀리 떨어진 값들을 그렇게 이상치로 표시할 수 있다는 이야기입니다. 다시 나온 이상치 부분들은 데이터를 분석하는 사람이 알아서 판단하여 처리해주면 되겠습니다.
명목형 변수의 극단치(특이값) 처리
이제 명목형 변수에서는 극단치를 어떻게 파악하고, 또 그것을 어떻게 처리할 수 있는 지 살펴볼까요?
다음은 예시 코드입니다.
여기에서는 먼저 백분위(%)를 통해 각 명목형 값들의 포함 비율을 먼저 살펴본 뒤, barplot을 통해 시각적으로 이를 표현합니다.
이 경우 따로 극단치라할만한 것은 없어보여서 처리하지 않았습니다. 그렇지만 만약 막대 그래프에서 한 명목형 값의 개수가 상대적으로 엄청 작게 나온다거나 하는 경우엔 그 값을 따로 빼버려야겠죠.
library(ggplot2)
library(patchwork) # 그래프 모아서 보기
# 명목형 변수 극단치 파악 - bar plot
prop.table(table(data$상권구분코드..발달상권.1.골목상권.2.기타.3..))
prop.table(table(data$대표상권유형))
prop.table(table(data$소속구역...소속구역.한정.1.소속구역.반경.500m.2.소속구역.반경.1000m.3.)) # 명목형 변수 분포 확인
# bar plot -- 눈에 띄는 극단치는 없음
p1 <- ggplot(data, aes(x=상권구분코드..발달상권.1.골목상권.2.기타.3..)) +
geom_bar(width=0.7, fill="steelblue")
p2 <- ggplot(data, aes(x=대표상권유형)) +
geom_bar(width=0.7, fill="steelblue")
p3 <- ggplot(data, aes(x=소속구역...소속구역.한정.1.소속구역.반경.500m.2.소속구역.반경.1000m.3.)) +
geom_bar(width=0.7, fill="steelblue")
p1 + p2 + p3 # 그래프 모아서 보기
그럼 극단치가 나온 경우에는 어떻게 처리해야하나요?
그래서 다음 예제 코드를 통해 임의로 변수 필터링을 시켜봤습니다.
수가 많은 상업지역, 역세권, 주거지역 쪽 데이터 쪽만 뽑은 새로운 데이터셋을 구성해보았습니다.
만일 극단치가 나온 상황이라해도, 이렇게 극단치 이외의 명목 값들만 뽑아서 새로운 데이터셋을 만들 수 있겠죠. 이렇게 극단치인 값을 배제하여 처리할 수 있습니다.
# 기존 명목형 값
table(data$대표상권유형) # 기존 명목형 값 분포
ggplot(data, aes(x=대표상권유형)) +
geom_bar(width=0.7, fill="steelblue")
# 필터링
new_data <- subset(data, c(대표상권유형 == "상업지역" | 대표상권유형 == "역세권" | 대표상권유형 == "주거지역"))
# 새로운 명목형 값
table(new_data$대표상권유형) # 새로운 명목형 값 분포
ggplot(new_data, aes(x=대표상권유형)) +
geom_bar(width=0.7, fill="steelblue") # 시각화
이상으로 결측치와 이상치(= 극단치, 특이치)를 처리하는 간단한 방법을 소개하는 것이 끝났네요.
이 방법 이외에도 무수히 많은 방법들이 존재하고요, 해당 값을 제거하는 것이 나을 지 아닐 지 판단하는 객관적 방법들도 여러 가지입니다.
저와 같은 경우는 약간은 주관적인 기준으로 간단하게 처리해본 것입니다. 따라서, 다른 여러가지 인터넷 문서들도 함께 참고하여, 상황에 따라 올바른 데이터 정제를 수행하는 것을 추천합니다.
제 포스팅이 여러분께 도움이 되었으면 좋겠습니다. 도움이 되었다면 하단의 공감(좋아요) 버튼 눌러주세요
댓글과 지적 모두 환영합니다!
'IT > 데이터 과학 & 인공지능' 카테고리의 다른 글
[데이터 사이언스] 검색 엔진은 어떤 원리로 작동할까? + tf-idf 유사도 예제 풀이 (0) | 2022.06.27 |
---|---|
[데이터 사이언스 / R] 주성분 분석(PCA), 활용 예시 (feat. k-means 군집화) (0) | 2022.06.03 |
[데이터 사이언스] R - 숫자가 아닌 값(범주형,명목형)들을 숫자로 변환(매핑) (0) | 2022.04.29 |
[데이터 사이언스 / R] iris 데이터셋을 이산화. 수치형(연속형) 변수를 명목형 변수로 변환 (0) | 2022.04.08 |