데이터 분석하거나 시각화 하다보면 이상적인 범위를 벗어나 데이터 분포에 영향을 미치는 데이터들이 존재하는데 이를 이상값이라고 한다.
국민 소득을 예로 들어 설명을 하면,
A그룹의 연간 소득 분포가 [5천만, 6천만, 4,800만, 6,200만, 7천만, 15억8천만, 39만]이 있다고 하면 이 그룹의 연간 평균소득은 2억6,719만원이다. 이런 수치는 이 그룹의 연간소득을 적절히 설명하지못한다.
이 때 일반적인 분포에서 벗어난 데이터인 15억8천만, 39만원이 이상값이라고 할 수 있다.
# 이상값 유형
이상값은 앞에 설명한 것 처럼 수치가 너무 크거나 작아 분포에 영향을 끼치는 것 외에도 다른 유형들이 있다.
구분 | 설명 |
점 이상값 | 일반적인 데이터들과 값의 차이가 큰 데이터 |
상황적 이상값 | 상황에 따라서 정상일수도, 비정상일수도 있는 데이터 |
집단적 이상값 | 개별 데이터일 때는 이상이 없지만, 이러한 데이터들의 집단에서는 비정상적인 패턴을이 보이는 데이터들의 집합 |
이러한 이상값들은 단위의 정규화가 되지 않았거나, 고의적으로 이상값을 삽입한 경우, 측정/실험 오류, 자연 변형 등에 의해 발생한다.
# 이상 데이터 탐색
직관적으로 보이는 값들은 이상값으로 처리할 수 있지만, 데이터 수가 많거나 일반적인 그래프로 발견할 수 없는 데이터들은 통계적인 기법을 이용해서 이상값을 탐색해낸다.
- Z-검정 : 정규분포의 Z-score를 이용해서 표준정규분포를 벗어나는 유의수준의 값들을 이상값으로 검출하는 방법
- 카이스퀘어 검정 : 자유도가 1인 카이스퀘어 분포를 따르는 통계량의 임계치보다 큰 경우 하나 이상의 이상값이 존재한다고 판단한다. 데이터가 정규분포를 만족시하거나, 데이터의 수가 적을 때 이용한다
- 사분위수 범위 : 전체 데이터 분포를 25%, 50%, 75%, 100%로 구분한 사분위 범위에서 제3분위수(75%)에서 제1분위수(25%)의 값을 뺀 IQR의 MAX와 MIN 값의 밖에 있는 값들을 이상값으로 판단
- 회귀 진단 : 해당 데이터 집단에 회귀 모델을 적용했을 때 예상 값의 범위 밖에 있는 데이터들을 이상값으로 판단
- 거리 탐색 기법: 관측치 사이의 거리를 이용해서 평균적인 데이터 간의 거리보다 벗어난 데이터를 이상값으로 판단, 대표적으로 k-NN 알고리즘을 들 수 있다
- 밀도 기반 탐색 기법: 상대적인 밀도를 고려하여 이상값을 탐지, LOF, DBSCAN, k-Means 알고리즘등이 있다
#데이터 이상값 처리
이상값은 분석의 대상이 되지 않는 경우가 많아 삭제하는 방법을 자주 사용한다.
삭제 이외에는 극단치의 기준을 적용하여 조정하거나 삭제하는 방법 또는 다른 값으로 대치하는 방법을 사용하기도 한다.
(극단치 기준 : 평균&표준편차, 사분위수 극단값 등)
#실습
- Z-검정을 이용한 이상값 탐색 및 처리
import random
data = list(np.random.randint(1, 100, size=3000))
[1~100]의 범위를 값으로 가지는 3000개 데이터를 생성하고, 이를 정규화해서 살펴보고 다시 이상값을 추가한 후 확인해볼 것이다.
구분 | raw 데이터 값의 분포 | 이상값 추가 데이터 분포 |
정규분포 | ![]() |
![]() |
표준정규분포 | ![]() |
![]() |
- <이상값 추가 코드>
ol_data = data.copy()
ol_no = 10
for i in range(ol_no):
rand_no = random.randint(0, len(data))
ol_data.insert(rand_no, ol_data[rand_no]*2)
<정규분포 출력 코드>
# raw 데이터 정규분포
pdf = stats.norm.pdf(np.sort(data), data_mean, data_std)
plt.figure()
plt.plot(np.sort(data), pdf)
# 이상값 추가 데이터는 데이터 추가 이후 같은 방법으로 시행
<표준정규분포 출력 코드>
# 데이터 별로 z-score을 환산한 후 적용
std_list = []
for i in data:
z = (i - data_mean) / data_std
std_list.append(z)
ol_data_mean = np.mean(std_list)
ol_data_std = np.std(std_list)
ol_pdf = stats.norm.pdf(np.sort(std_list), ol_data_mean, ol_data_std)
plt.figure()
plt.plot(np.sort(std_list), ol_pdf)
# 이상값 추가 이후 동일
<이상값 제거>
# |z-score|이 2가 넘는 것들을 삭제, z-score > 2의 유의수준 : 98%
for i in ol_std_list:
if i > 2:
ol_std_list.remove(i)
if i < -2:
ol_std_list.remove(i)
- 사분위값 검정(Box plot)
data2 = pd.DataFrame(np.random.randn(100, 3), columns=['A', 'B', 'C'])
data2.head()
±3 이내의 값을 100개씩 가지는 3개의 column을 가진 dataframe을 가지고 boxplot을 그려 이상값의 존재를 파악하려한다.
<사분위>
<Box plot>
boxplot을 확인해보니 B에서 IQR의 MIN 보다 작은 이상값들이 존재함을 확인할 수 있다.
<이상값 탐색>
def get_ol(df, col, weight=1.5):
Q_25 = np.percentile(df[col].values, 25)
Q_75 = np.percentile(df[col].values, 75)
IQR = Q_75 - Q_25
IQR_weight = IQR*weight
low = Q_25 - IQR_weight
high = Q_75 + IQR_weight
ol_idx = df[col][(df[col] < low) | (df[col] > high)].index
return ol_idx
이상값들이 어떤게 있는지 위 함수를 사용해 도출한 결과,
[19, 91, 99]번째 index의 값이 이상값임을 알 수 있음.
(random을 통해서 산출한 데이터이므로 시행마다 결과가 다를 수 있음)
<이상값 drop>
data2.drop(ol_idx, axis=0, inplace=True)
sns.boxplot(data=data2)
이렇게 이상값을 제거할 수 있다.
※위 과정은 행정안전부, 한국지능정보사회진흥원, CSLEE 컨소시엄, KPC에서 진행하는 데이터 분석 청년인재 양성 전문과정에서 제공하는 교재의 일부분을 활용해 작성했음을 밝힙니다.
'데이터 분석 > 파이썬' 카테고리의 다른 글
[파이썬] 범주형 데이터의 실수화 (labeling, one-hot encoding) (0) | 2022.07.06 |
---|---|
[파이썬] 워드 클라우드 (0) | 2022.06.29 |
파이썬 클래스 (0) | 2021.11.14 |
데이터 시각화 그래프 (0) | 2021.06.29 |
numpy 라이브러리 (0) | 2021.03.23 |