bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
3 NaN NaN NaN NaN
271 NaN NaN NaN NaN
bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
3 43.92193 17.15117 200.915205 4201.754386
271 43.92193 17.15117 200.915205 4201.754386
index 0
0 bill_length_mm 43.921930
1 bill_depth_mm 17.151170
2 flipper_length_mm 200.915205
3 body_mass_g 4201.754386
species bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
3 Adelie NaN NaN NaN NaN
271 Gentoo NaN NaN NaN NaN
species bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
3 Adelie 38.791391 18.346358 189.953642 3700.662252
271 Gentoo 47.504878 14.982114 217.186992 5076.016260
species sex
3 Adelie NaN
8 Adelie NaN
9 Adelie NaN
10 Adelie NaN
11 Adelie NaN
47 Adelie NaN
178 Gentoo NaN
218 Gentoo NaN
256 Gentoo NaN
268 Gentoo NaN
271 Gentoo NaN
277 Chinstrap NaN
list_modes = []for col in num_cols: list_modes.append(df_mode[col].mode()[0]) df_mode[col] = df_mode[col].fillna(df_mode[col].mode()[0])print(df_mode.loc[na_index, ['species']+num_cols])print(pd.Series(list_modes, index=num_cols).reset_index())
species sex
3 Adelie male
8 Adelie male
9 Adelie male
10 Adelie male
11 Adelie male
47 Adelie male
178 Gentoo male
218 Gentoo male
256 Gentoo male
268 Gentoo male
271 Gentoo male
277 Chinstrap male
index 0
0 sex male
위 예제는 전체 컬럼 기준으로 최빈값을 계산 후 결측치를 대체한다. 아래 예제는 범주별 최빈값을 결측치에 대체하는 코드이다.
list_modes = []for col in num_cols: list_modes.append(df_mode[col].mode()[0]) df_mode[col] = df_mode.groupby(['species'])[col].transform(lambda x: x.mode()[0])print(df_mode.loc[na_index, ['species']+num_cols])
species sex
3 Adelie male
8 Adelie male
9 Adelie male
10 Adelie male
11 Adelie male
47 Adelie male
178 Gentoo male
218 Gentoo male
256 Gentoo male
268 Gentoo male
271 Gentoo male
277 Chinstrap female
모델링
import pandas as pdfrom palmerpenguins import load_penguinsfrom sklearn.experimental import enable_iterative_imputerfrom sklearn.impute import IterativeImputerfrom sklearn.ensemble import RandomForestRegressor# 1. 데이터셋 로드penguins = load_penguins()# 2. 수치형 데이터 선택numeric_cols = ['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g']df_numeric = penguins[numeric_cols]# 대체 전 결측치 확인print("대체 전 결측치 상황:")print(df_numeric.isnull().sum())na_index = df_numeric.loc[df_numeric.isna().any(axis=1), :].indexprint(df_numeric.loc[na_index, :])# 3. IterativeImputer 설정imputer = IterativeImputer( estimator=RandomForestRegressor(n_estimators=10, random_state=42), max_iter=10, random_state=42)# 4. 결측치 대체 수행df_imputed = imputer.fit_transform(df_numeric)# 5. 결과를 다시 데이터프레임으로 변환df_final = pd.DataFrame(df_imputed, columns=numeric_cols)print("\n대체 후 결측치 상황:")print(df_final.isnull().sum())print(df_final.loc[na_index, :])# 원본 데이터와 합치기 (필요한 경우)penguins[numeric_cols] = df_final
대체 전 결측치 상황:
bill_length_mm 2
bill_depth_mm 2
flipper_length_mm 2
body_mass_g 2
dtype: int64
bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
3 NaN NaN NaN NaN
271 NaN NaN NaN NaN
대체 후 결측치 상황:
bill_length_mm 0
bill_depth_mm 0
flipper_length_mm 0
body_mass_g 0
dtype: int64
bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
3 51.89 19.23 205.9 4010.0
271 51.89 19.23 205.9 4010.0
다음은 범주별 모델링을 적용한 예제이다.
import pandas as pdfrom sklearn.experimental import enable_iterative_imputerfrom sklearn.impute import IterativeImputerfrom sklearn.ensemble import RandomForestRegressor# 1. 데이터셋 로드penguins = load_penguins()# 대체에 사용할 수치형 컬럼 정의numeric_cols = ['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g']# 2. 그룹별 대체를 수행할 함수 정의def impute_by_group(group):# 각 그룹 내에서 수치형 데이터만 추출 group_numeric = group[numeric_cols]# 모델 기반 대치기 설정 (RandomForest 사용) imputer = IterativeImputer( estimator=RandomForestRegressor(n_estimators=10, random_state=42), max_iter=10, random_state=42 )# 데이터가 모두 결측치인 경우 등을 대비해 예외 처리 후 대치if group_numeric.isnull().all().all():return group imputed_values = imputer.fit_transform(group_numeric) group[numeric_cols] = imputed_valuesreturn group# 3. species 컬럼을 기준으로 그룹화하여 함수 적용# 성별(sex)에 결측치가 있는 경우도 있으므로 전체 데이터프레임 유지penguins_imputed = penguins.groupby('species', group_keys=False).apply(impute_by_group)# 4. 결과 확인print("종별 대체 후 결측치 현황:")print(penguins_imputed[numeric_cols].isnull().sum())na_index = df_numeric.loc[df_numeric.isna().any(axis=1), :].indexprint(penguins_imputed.loc[na_index, :])# 특정 종의 결과 예시 출력 (Adelie)print("\nAdelie 종의 요약 통계량 (대체 후):")print(penguins_imputed[penguins_imputed['species'] =='Adelie'][numeric_cols].describe())
종별 대체 후 결측치 현황:
bill_length_mm 0
bill_depth_mm 0
flipper_length_mm 0
body_mass_g 0
dtype: int64
species island bill_length_mm bill_depth_mm flipper_length_mm \
3 Adelie Torgersen 37.25 18.06 184.5
271 Gentoo Biscoe 50.91 15.84 225.0
body_mass_g sex year
3 3715.0 NaN 2007
271 5330.0 NaN 2009
Adelie 종의 요약 통계량 (대체 후):
bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
count 152.000000 152.000000 152.000000 152.000000
mean 38.781250 18.344474 189.917763 3700.756579
std 2.657513 1.212837 6.532761 457.046652
min 32.100000 15.500000 172.000000 2850.000000
25% 36.775000 17.500000 185.750000 3350.000000
50% 38.800000 18.400000 190.000000 3700.000000
75% 40.725000 19.000000 195.000000 4000.000000
max 46.000000 21.500000 210.000000 4775.000000
이상치 처리
이상치는 데이터 패턴이나 범위를 크게 벗어난 값을 의미한다. 이러한 이상치는 다음과 같은 방법으로 탐지가 가능하다. 탐지된 이상치는 상황 및 모델 특성에 따라 삭제, 대체, 변환 등으로 처리한다.