데이터/데이터 분석

데이터 분석 이상치 처리 (Z-score,IQR)

Jerry_K 2023. 10. 21. 10:33

이상치 처리 방법 

  1. 제거 : 이상치를  제거하는 방법이다. 간단하지만 유효한 데이터일 경우 손실이 발생.
  2. 대체 : 이상치를 대체하는 방법이다. 평균, 중앙값, 최빈값 등으로 대체하여 사용.
  3. 범주화 : 연속형 변수를 구간별로 나누고 이상치를 특정 구간에 할당.
  4. 변환 : 이상치를 왜곡시키거나 조정한다.  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개의 가격이고, 그 값에 대한 평균이 필요했다. 

내가 구하고자하는 평균에는 이상치의 값들은 필요없다는 생각을 가져 이상치를 제거한 것 이다.

 

하지만 이상치를 무조건 지워서는 안된다.  이상치가 중요 데이터일 수 있기 때문이다. 

그거에 대한 판단은 개개인이 하는 것이지, 수식같은걸로 확정 지을 수 없다고 생각한다.