import pandas as pd
#데이터셋 불러오기
df = pd.read_csv("C:/Users/isabe/Downloads/preprocessing_students.csv", sep = ',')
print(df.head())
id name sex height weight IQ mid_score final_score employed
0 1 홍길동 male 173 62.0 109.0 68.0 78 대기업
1 2 김홍익 female 165 53.0 NaN 91.0 82 공기업
2 3 오나라 female 173 NaN 121.0 NaN 55 창업
3 4 이실장 male 178 78.0 107.0 NaN 56 미취업
4 5 차도남 male 165 82.0 125.0 78.0 74 공기업
print(df.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 20 entries, 0 to 19
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id 20 non-null int64
1 name 20 non-null object
2 sex 20 non-null object
3 height 20 non-null int64
4 weight 16 non-null float64
5 IQ 14 non-null float64
6 mid_score 14 non-null float64
7 final_score 20 non-null int64
8 employed 18 non-null object
dtypes: float64(3), int64(3), object(3)
memory usage: 1.5+ KB
#isnull()의 true 개수 합해서 확인하기
print(df.isnull().sum(axis = 0)) #axis = 0: 열기준 , 1 : 행기준
id 0
name 0
sex 0
height 0
weight 4
IQ 6
mid_score 6
final_score 0
employed 2
dtype: int64
import klib
import warnings
warnings.filterwarnings(action = 'ignore')
#결측치 프로파일링 플롯
print(klib.missingval_plot(df))

#결측치에 대한 프로파일링 플롯
print(klib.missingval_plot(df, sort = True))

#상관관계 플롯
print(klib.corr_plot(df))

weight와 height가 강한 양의 상관관계(0.78)를 보인다.
IQ와 mid_score가 양의 상관관계(0.59), mid_score와 final_score가 양의 상관관계(0.53)을 보인다.
import matplotlib.pyplot as plt
plt.rc('font', family = 'Malgun Gothic')
#범주형 변수에 대한 분석
print(klib.cat_plot(df))

#결측치가 있는 변수의 분표 확인하기
print(klib.dist_plot(df.weight))
print(klib.dist_plot(df.IQ))
print(klib.dist_plot(df.mid_score))

특정한 패턴이 보이지 않음

중간 영역대의 밀도가 낮은 것으로 보아 중간 영역대의 데이터가 누락되었음

낮은 점수대의 데이터가 누락되었음
결측치의 비율에 따른 처리 방법
10% 미만 : 제거 또는 치환
10% 이상 20% 미만 : 모델 기반 처리
20% 이상 : 모델 기반 처리
제거(deletion)
: MCAR(완전 무작위 결측)일 때 사용 가능
: 데이터의 손실이 발생 -> 자유도 감소 -> 통계적 검정력 저하
: 표본의 수가 충분하고 결측값이 10-15% 이내일 때에는 결측값을 제거한 후 분석해도 결과에 크게 영향을 주지 않음
대체(imputation)
: 표본 평균과 같은 대표값으로 대체할 경우 -> 대표값 데이터가 많아짐 -> 잔차 변동이 줄어듬 -> 잘못된 통계적 결론 유도
: 모수 추정 시 편향(bias) 발생
모델 기반 처리
: 결측치를 예측하는 새로운 모델을 구성하고 이를 기반으로 결측치 채워나가는 방식
: 변수의 특성에 따라 Knn, PolyRegression 등 시행 가능
: R 프로그램 패키지인 Mice 함수 사용 가능

import pandas as pd
#listwise deletion
df_listwise = df.dropna()
#pairwise deletion
df_pairwise = df.dropna(subset = ['weight', 'mid_score'])
print(f'original data:\n {df}\n')
print(f'Listwise Deletion:\n {df_listwise}\n')
print(f'Pairwise Deletion:\n {df_pairwise}\n')
original data:
id name sex height weight IQ mid_score final_score employed
0 1 홍길동 male 173 62.0 109.0 68.0 78 대기업
1 2 김홍익 female 165 53.0 NaN 91.0 82 공기업
2 3 오나라 female 173 NaN 121.0 NaN 55 창업
3 4 이실장 male 178 78.0 107.0 NaN 56 미취업
4 5 차도남 male 165 82.0 125.0 78.0 74 공기업
5 6 설빛가람 female 154 45.0 132.0 78.0 82 대기업
6 7 김철수 male 187 NaN NaN 63.0 65 미취업
7 8 이영희 female 163 61.0 128.0 74.0 89 중소기업
8 9 김용식 male 167 52.0 NaN 79.0 95 NaN
9 10 풍다희 female 162 56.0 NaN NaN 35 중견기업
10 11 최창현 male 175 61.0 NaN NaN 62 대기업
11 12 남궁선웅 male 176 73.0 108.0 87.0 87 창업
12 13 봉문혁 male 185 97.0 100.0 47.0 67 미취업
13 14 정윤혜 female 158 44.0 103.0 NaN 55 중소기업
14 15 오수경 female 169 55.0 120.0 88.0 65 미취업
15 16 노보선 female 172 89.0 121.0 98.0 94 중견기업
16 17 복하민 female 157 NaN NaN NaN 62 중소기업
17 18 한동진 male 156 42.0 125.0 89.0 73 NaN
18 19 고유진 female 165 NaN 104.0 76.0 89 대기업
19 20 풍진태 male 169 63.0 134.0 98.0 98 창업
Listwise Deletion:
id name sex height weight IQ mid_score final_score employed
0 1 홍길동 male 173 62.0 109.0 68.0 78 대기업
4 5 차도남 male 165 82.0 125.0 78.0 74 공기업
5 6 설빛가람 female 154 45.0 132.0 78.0 82 대기업
7 8 이영희 female 163 61.0 128.0 74.0 89 중소기업
11 12 남궁선웅 male 176 73.0 108.0 87.0 87 창업
12 13 봉문혁 male 185 97.0 100.0 47.0 67 미취업
14 15 오수경 female 169 55.0 120.0 88.0 65 미취업
15 16 노보선 female 172 89.0 121.0 98.0 94 중견기업
19 20 풍진태 male 169 63.0 134.0 98.0 98 창업
Pairwise Deletion:
id name sex height weight IQ mid_score final_score employed
0 1 홍길동 male 173 62.0 109.0 68.0 78 대기업
1 2 김홍익 female 165 53.0 NaN 91.0 82 공기업
4 5 차도남 male 165 82.0 125.0 78.0 74 공기업
5 6 설빛가람 female 154 45.0 132.0 78.0 82 대기업
7 8 이영희 female 163 61.0 128.0 74.0 89 중소기업
8 9 김용식 male 167 52.0 NaN 79.0 95 NaN
11 12 남궁선웅 male 176 73.0 108.0 87.0 87 창업
12 13 봉문혁 male 185 97.0 100.0 47.0 67 미취업
14 15 오수경 female 169 55.0 120.0 88.0 65 미취업
15 16 노보선 female 172 89.0 121.0 98.0 94 중견기업
17 18 한동진 male 156 42.0 125.0 89.0 73 NaN
19 20 풍진태 male 169 63.0 134.0 98.0 98 창업
결측치의 대체값으로 하나의 값 선정
mean, correlation, 회귀계수와 같은 파라미터 추정 시 편향 발생 가능성 높다.
추정 편향으로 인해 결측치 제거하는 것보다 통계적 특성이 나빠질 수 있다.
종류
from sklearn.impute import SimpleImputer
df_imputed = pd.DataFrame.copy(df)
#110대가 결측인 IQ는 mean으로 대체
df_imputed[['IQ']] = SimpleImputer(strategy = 'mean').fit_transform(df[['IQ']])
#비대칭 분포를 갖는 mid_score은 median으로 대체
df_imputed[['mid_score']] = SimpleImputer(strategy = 'median').fit_transform(df[['mid_score']])
#범주형 employed는 Hot Deck로 대체
df_imputed['employed'].fillna(method = 'bfill', inplace = True)
# height와 양의 상관관계가 있는 weight는 Stochastic regression으로 대체
from sklearn.linear_model import LinearRegression
import numpy as np
# 결측치가 있는 인덱스 검색
idx = df.weight.isnull() == True
# 학습을 위한 데이터 세트 분리
X_train, X_test, y_train = df[['height']][~idx], df[['height']][idx], df[['weight']][~idx]
# 선형회귀모형 인스탄스 생성 후 학습
lm = LinearRegression().fit(X_train, y_train)
# 예측값 + 변동값하여 결측치를 대체
df_imputed.loc[idx, 'weight'] = lm.predict(X_test) + 5*np.random.rand(4,1)
print(df_imputed)
id name sex height weight IQ mid_score final_score \
0 1 홍길동 male 173 62.000000 109.000000 68.0 78
1 2 김홍익 female 165 53.000000 116.928571 91.0 82
2 3 오나라 female 173 71.145130 121.000000 78.5 55
3 4 이실장 male 178 78.000000 107.000000 78.5 56
4 5 차도남 male 165 82.000000 125.000000 78.0 74
5 6 설빛가람 female 154 45.000000 132.000000 78.0 82
6 7 김철수 male 187 93.305695 116.928571 63.0 65
7 8 이영희 female 163 61.000000 128.000000 74.0 89
8 9 김용식 male 167 52.000000 116.928571 79.0 95
9 10 풍다희 female 162 56.000000 116.928571 78.5 35
10 11 최창현 male 175 61.000000 116.928571 78.5 62
11 12 남궁선웅 male 176 73.000000 108.000000 87.0 87
12 13 봉문혁 male 185 97.000000 100.000000 47.0 67
13 14 정윤혜 female 158 44.000000 103.000000 78.5 55
14 15 오수경 female 169 55.000000 120.000000 88.0 65
15 16 노보선 female 172 89.000000 121.000000 98.0 94
16 17 복하민 female 157 49.637373 116.928571 78.5 62
17 18 한동진 male 156 42.000000 125.000000 89.0 73
18 19 고유진 female 165 59.299214 104.000000 76.0 89
19 20 풍진태 male 169 63.000000 134.000000 98.0 98
employed
0 대기업
1 공기업
2 창업
3 미취업
4 공기업
5 대기업
6 미취업
7 중소기업
8 중견기업
9 중견기업
10 대기업
11 창업
12 미취업
13 중소기업
14 미취업
15 중견기업
16 중소기업
17 대기업
18 대기업
19 창업
import numpy as np
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
# 데이터 세트
X_train = [[33, np.nan, .153], [18, 12000, np.nan], [np.nan, 13542, .125]]
X_test = [[45, 10300, np.nan], [np.nan, 13430, .273], [15, np.nan, .165]]
# mice 인스턴스 생성
mice = IterativeImputer(max_iter=10, random_state=0)
mice.fit(X_train)
np.set_printoptions(precision=5, suppress=True)
print('X_train MICE: \n', mice.transform(X_train))
print('X_test MICE: \n', mice.transform(X_test))
X_train MICE:
[[ 33. 12770.99952 0.153 ]
[ 18. 12000. 0.181 ]
[ 48.00002 13542. 0.125 ]]
X_test MICE:
[[ 45. 10300. 0.2427 ]
[ 45.82103 13430. 0.273 ]
[ 15. 11845.80217 0.165 ]]
import numpy as np
from sklearn.impute import KNNImputer
knn = KNNImputer(n_neighbors=2, weights="uniform")
knn.fit(X_train)
print('X_train KNN: \n', knn.transform(X_train))
print('X_test KNN: \n', knn.transform(X_test))
X_train KNN:
[[ 33. 12771. 0.153]
[ 18. 12000. 0.139]
[ 25.5 13542. 0.125]]
X_test KNN:
[[ 45. 10300. 0.139]
[ 25.5 13430. 0.273]
[ 15. 12771. 0.165]]