(150 000, 6) 중에서 3,000 개의 결측치 셀
import pandas as pd
import numpy as np
import category_encoders as ce
from sklearn.impute import KNNImputer
from sklearn.preprocessing import RobustScaler
#######################작업 일지####################
## 하나의 변수만 missing일 때만 해봅시다
## =-> 이제 성공적으로 완수했으니까 그 다음 단계로 넘어가서
## 여러개의 category가 missing인 경우도 해봅시다
## => 이제 성공적으로 완수했으니까 그 다음 단계로 넘어가서
## 1. missing_col의 자동 탐색 및 => 해결(210314)
## 2. 자동으로 생성되는 #(한 col의 class)+1 col의 제거
## 3. scaling 작업도 해줘야 함 => 해결(210413)
## 4. num과 cate를 하나로 묶어주기 => 해결(210414)
## 5. class의 수에 따라서 진행할지 말지 선택하도록 하기
#######################작업 일지####################
####################### 버전 업 ####################
## 1. num=>cate or num& cate:
### 1-1 만약에 num=> cate를 따르게 한다면,
## pca를 해서 두번째 계산과정을 줄일 수 있도록 할 것
### 1-2 만약에 num&cate면 대폭 수정
## 2. class의 제한을 어떻게 둘 것인가?
### 2-1 절대적인 한계 설정
### 2-2 데이터 프레임 전체의 사이즈를 고려해서 이미 크다면
#### class 수를 조금만 풀어주고 작다면 충분히 고려해주기
################## 버전 업 #########################
##################알고리즘 개요####################
## 0. KNNImpute_num을 통해 numerical한 변수의 결측치는 미리 채운다
## 1. 원핫인코딩을 한다
## 2. 인코딩 과정에서 생략된 nan 값을 다시 입력해준다
## 3. KNNImpute_num을 통해 인코딩된 변수의 결측치를 대체한다
## 4. 평균이 산출되므로, 인코딩 값으로 변환한다(0 또는 1)
## 5. 디코딩 한다
## 끝!
##################알고리즘 개요####################
def KNNImpute(df):
# 명목형 에서 missing이 없으면 바로 num으로 가게 하고
# 만약 그게 아니라면 cate로 가게 하기
new_df=KNNImpute_num(df)
if new_df.isnull().sum!=0:
## 여기에 class의 수를 보는 조건문 넣기
new_df=KNNImpute_cate(new_df)
else: return new_df
def KNNImpute_num(df):
new_df=df.select_dtypes(include=np.number)
#입력된 데이터프레임 중에 Numerical한 column
cols=new_df.columns
#col 이름 저장
scaler=RobustScaler()
new_df=scaler.fit_transform(new_df)
imputer=KNNImputer(n_neighbors=5)
new_df=imputer.fit_transform(new_df)
new_df=pd.DataFrame(new_df, columns=cols)
new_df=scaler.inverse_transform(new_df)
for col in df.columns:
if col in cols:
df[col] = new_df[col]
#빠졌던 Categorical data를 다시 채워줌
return df
## df_miss: 불완전한 데이터 셋
## missing_col: 불완전한 categorical 컬럼 명, 리스트 형태로 넣어줌
## => 버전 업하면서 개선할 예정
def KNNImpute_cate(df_miss):
# 결측치 있는 명목형 변수 col 탐색
missing_col=list(df_miss.columns[df_miss.isnull().sum()!=0])
## 데이터프레임 내 존재하는 모든 명목형변수를 원핫 인코딩함(결측치 있던 없던)
cols_o=df_miss.select_dtypes(exclude=np.number).columns
#categorical 변수들 목록
one_en=ce.one_hot.OneHotEncoder(handle_missing="value")
x_one=one_en.fit_transform(df_miss,cols_o) #df_miss를 인코딩한 df
## step2 인코딩 되버린 결측치를 다시 nan값으로 변경
## 원핫인코딩을 하면 해당 col이 a_1, a_2, 이런 식으로 생성됨
## cols는 이렇게 파생된 모든 col을 저장한 리스트
index_total={}
cols_total={}
for i in range(len(missing_col)):
target_col=missing_col[i]
index_total[target_col]=list(df_miss.loc[df_miss[target_col].isna(),:].index) #missing 한 index 리스트
cols_total[target_col]=list(x_one.columns[x_one.columns.str.contains(pat = target_col)]) ## missing 한 col에서 파생된 col 리스트
x_one.loc[index_total[target_col],cols_total[target_col]]=np.nan # 결측치 값으로 바꿔주기
## step3 만들어둔 모둘 이용
x_one_imputed=KNNImpute_num(x_one)
## step 4 : 평균이 산출되므로, 인코딩 값으로 변환한다(0 또는 1)
## ::: 동일 col 별로 묶어서 argmax를 한다 (a_1,a_2 중에서 가장 큰 값)
for j in range(len(missing_col)):
target_col=cols_total[missing_col[j]]
target_idx=index_total[missing_col[j]]
imputed_val=np.argmax(x_one_imputed.loc[target_idx,target_col].to_numpy(),axis=1)
long=range(len(target_col))
for i in range(len(target_idx)):
x_one_imputed.loc[target_idx[i],[target_col[imputed_val[i]]]]=1 #최대값을 1로 impute
cols_0=[target_col[j] for j in long if j!=imputed_val[i]]
x_one_imputed.loc[target_idx[i],cols_0]=0 # 그 외의 값 0으로 impute
## 6. 그런 다음에 디코딩을 한다
x_one_de=one_en.inverse_transform(x_one_imputed)
return x_one_de
## scaling 기능 붙이고 난후
오히려 잘못 대체한 경우가 많아진 것으로 봐서, 본 데이터 셋은 scaling 안 된 경우가 낫다는 것을 알 수 있음. 즉 numerical한 변수와 우리가 대체하고자 하는 column이 높은 상관성이 있으면 오히려 scaling하지 않은 것이 낫다. 그러나 우리가 그것을 데이터 셋을 뜯어보기 전에 알 수 있는 확률이 적다고 판단된다..
'머신러닝 > 아웃라이어, 결측치' 카테고리의 다른 글
fraud detection 을 통해보는 outlier algorithm (1) | 2021.04.14 |
---|---|
실루엣 분석Silhouette Analysis (0) | 2021.03.30 |
자기조직화지도 SOM (0) | 2021.03.30 |
알고리즘 간단 요약 및 비교 (0) | 2021.03.30 |
마할라노비스 거리Mahalanobis distance (0) | 2021.03.30 |
댓글