이상치 처리 방법
- 제거 : 이상치를 제거하는 방법이다. 간단하지만 유효한 데이터일 경우 손실이 발생.
- 대체 : 이상치를 대체하는 방법이다. 평균, 중앙값, 최빈값 등으로 대체하여 사용.
- 범주화 : 연속형 변수를 구간별로 나누고 이상치를 특정 구간에 할당.
- 변환 : 이상치를 왜곡시키거나 조정한다. ex ) 로그 변환
이 포스터에 제거 방법에 대해 다룰 예정이다.
이상치 제거에는 여러 방법이 있는데 사분위수 방법과 Z-score 방법에 대해 알아보자.
1. 사분위수 방법
먼저 데이터를 오름차순으로 정렬한다.
그리고 25%,75%(Q1,Q3)에 해당하는 위치 값을 구한다.
그러면 IQR (IQR = Q3-Q1)의 값을 구할 수 있는데 여기에 가중치를 곱한 후 범위에 벗어나는 값을 이상치로 처리한다.
즉 , data > Q1 - (IQR * weight) & data < Q3 - (IQR * weight) 의 범위만을 이상치가 아닌 값으로 간주한다.
실제 예제를 통해 알아보자.
data = np.array([ 6900, 6900, 25800, 5400, 2200, 1700, 2930, 2920, 12900,
15900, 19900, 9900, 29800, 1190, 5600, 8000, 18800, 5500,
2300, 6900, 560, 1600, 71100, 2410, 4460, 3850, 5900,
3300, 1350, 4720, 725, 3700, 37900, 2900, 3792, 29900,
11840, 1850, 22800, 3700, 5200, 5700, 5900, 990, 1200,
4900, 5190, 15600, 2110, 895, 528, 8700, 1462, 3110,
1931, 4590, 4400, 6455, 1870, 6550, 1830, 2320, 6690,
12900, 4900, 6700, 800, 14240, 730, 2000, 2000, 8660,
1510, 1377, 5500, 2800, 5440, 2730, 1068, 1110, 11140,
4000, 3730, 5900, 2160, 1830, 2590, 1270, 720, 3300,
3930, 790, 5970, 31600, 5700, 3360, 5370, 3900, 1320,
690])
이런 데이터를 만들었고 간단히 데이터의 분포를 봐보자.
fig, axs = plt.subplots(1, 2, figsize=(10,6))
axs[0].boxplot(data);
axs[1].hist(data, bins=100);
70000 같이 눈에 띄는 이상치들이 보인다 .
def outlier_remove_q(data, weight=1.5):
quantile_25 = np.percentile(data, 25)
quantile_75 = np.percentile(data, 75)
IQR = quantile_75 - quantile_25
IQR_weight = IQR*weight
lowest = quantile_25 - IQR_weight
highest = quantile_75 + IQR_weight
outlier = data[(data < lowest) | (data > highest)]
removed_data = data[(data >=lowest) & (data <= highest)]
return removed_data, outlier
간단하게 코드를 설명하면, np.percentile(data, 25)는 25% 위치에 해당하는 값을 주는 함수이다.
이렇게 Q3 와 Q1을 구하여 IQR 값을 구하고 , 가중치(weight)를 곱해준다. (일반적으로 가중치는 1.5로 한다.)
outlier은 제외 된 데이터들이고, removed_data는 이상치를 제거하고 남은 값이다.
removed_data, outlier = outlier_remove_q(data)
print(f"이상치 제저 후 데이터: {removed_data} \n\n이상치 : {outlier}")
이상치 제거 후 데이터화 이상치를 출력했다.
이상치 제거 후 데이터는 비교적 골고루 분포되어 있는걸 볼 수 있다.
fig, axs = plt.subplots(1, 2, figsize=(10,6))
axs[0].boxplot(removed_data);
axs[1].hist(removed_data, bins=100);
좀 더 시각적으로 확인하면 이렇다.
확연히 이상치 제거 전 분포와 차이를 볼 수 있다.
2. Z-score 방법
Z-score은 데이터가 평균에서 표준 편차의 몇 배만큼 떨어져 있는지를 나타내는 값이다.
따라서 Z-score 방법은 평균을 기준으로 얼마나 떨어졌는데 표준화하여 비교 한다.
일반적으로 threshold = 3으로 하여 |Z-score| > 3 인 값들을 이상치로 처리한다.
위의 data를 그대로 써서 이번에는 Z-score 방법으로 이상치를 처리해보자.
def outlier_remove_z(data, threshold=3):
z_scores = np.abs(data - np.mean(data)) / np.std(data)
outlier = data[z_scores>threshold]
removed_data = data[z_scores < threshold]
return removed_data, outlier
threshold = 3 으로 정해두고 , z_score의 값을 구한다 .
removed_data, outlier = outlier_remove_z(data)
print(f"이상치 제저 후 데이터: {removed_data} \n\n이상치 : {outlier}")
이상치 제거후 데이터와 이상치에 대해 출력 값
fig, axs = plt.subplots(1, 2, figsize=(10,6))
axs[0].boxplot(removed_data);
axs[1].hist(removed_data, bins=100);
z-score 방식으로 위의 data를 출력해보니 꽤 넓은 범위까지 이상치 아닌 값으로 나왔다.
히스토그램을 봐보면 나름 골고루 분포되었다.
지금 나는 네이버 스마트 스토어 데이터 분석을 하고 있다.
위의 data는 특정 키워드의 top 100개의 가격이고, 그 값에 대한 평균이 필요했다.
내가 구하고자하는 평균에는 이상치의 값들은 필요없다는 생각을 가져 이상치를 제거한 것 이다.
하지만 이상치를 무조건 지워서는 안된다. 이상치가 중요 데이터일 수 있기 때문이다.
그거에 대한 판단은 개개인이 하는 것이지, 수식같은걸로 확정 지을 수 없다고 생각한다.
'데이터 > 데이터 분석' 카테고리의 다른 글
[Python] 로또는 운일까 ? (로또 데이터 분석) - 1편. 로또 정보 수집하기 (0) | 2024.07.05 |
---|---|
파이썬 판다스 (concat / merge) (0) | 2024.03.26 |
파이썬 판다스 (groupby / pivot_table) (0) | 2024.03.18 |
T-test 정리 (0) | 2023.10.28 |
파이썬 판다스 (시리즈/데이터프레임/인덱싱/멀티인덱싱) (0) | 2023.08.22 |