Data Analysis

데이터 전처리, 결측치, 이상치, 극단치

김심슨 2025. 5. 26. 15:59

1. 결측치 처리 

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'name': ['홍길동', '강감찬', np.nan, '이순신'],
    'score': [100, 90, 80, np.nan]
})

# 결측치 확인하기 
pd.isna(df)

# 결측치 개수 확인
pd.isna(df).sum()

# 결측치 제거 
df.dropna(subset=['score']) #특정 열에서만 결측치 제거 
df.dropna(subset=['name','score']) # 두 열 모두 NaN인 경우만 제거

# 결측치 대체 
df.loc[[2], ['name']] = '유관순'   # 이름 결측치 직접 입력 
df.loc[[3],['score']] = 70   # 점수 결측치 대체 
df['compscore'] = df['score'] - 10
df['compscore'] = df['compscore'].fillna(80) # 컴스코어 결측치 80으로 대체

 

* 왜 compscore 파생 변수를 생성한 걸까? 

score - 10, 80점으로 채운 이유는 "보정점수"를 만든 것, 이 자체는 분석 목적에 따라 달라질 수 있음. 핵심은 어떻게 파생변수를 만들고 결측치를 처리하는지를 익히는 것 

+ 평균값, 중앙값으로 채우기도 함

df['score'].fillna(df['score'].mean())      # 평균으로 채우기
df['score'].fillna(df['score'].median())    # 중앙값으로 채우기

 

2. 이상치 처리 

df2 = pd.DataFrame({
    'name': ['홍길동', '강감찬', '도봉구'],  # 도봉구는 사람 이름 아님
    'score': [100, 120, 80]                # 120점은 점수 범위 초과
})

# 이상치를 결측치로 바꾸기 
df2['score'] = np.where(df2['score'] > 100, np.nan, df2['score'])

# 결측치로 대체된 이상치 제거 
df2 = df2.dropna(subset = ['score'])

 

3. 극단치 (outlier 정제) - boxplot 기준 

극단치가 들어가면 전체 평균이 왜곡될 수 있어 반드시 제거해야함 

import seaborn as sns
import matplotlib.pyplot as plt

mpg = pd.read_csv('assets/mpg.csv')
sns.boxplot(data=mpg, y='hwy')
plt.show()

# 사분위 수 계산 
Q1 = mpg['hwy'].quantile(.25)
Q3 = mpg['hwy'].quantile(.75)
IQR = Q3 - Q1 

downlimit = Q1 = 1.5 * IQR    # 4.5
uplimit = Q3 + 1.5 * IQR    # 40.5

# 극단치 제거 처리 (결측치로 만든 후 -> dropna)
mpg['hwy'] = np.where((mpg['hwy'] < downlimit) | (mpg['hwy'] > uplimit), np.nan, mpg['hwy'])
mpg = mpg.dropna(subset=['hwy'])

극단치 정제 전 / 후

4. 그룹별 평균 확인하기 - groupby 

print(mpg.groupby('drv').agg(mean_hwy=('hwy', 'mean')))

----- 출력 -----
      mean_hwy
drv    
------전-------
4    19.174757
f    28.160377
r    21.000000
------후-------
4    19.174757
f    27.728155
r    21.000000

=> 평균을 확인해서 평균의 변화를 본다.