handling missing value
missing value를 다뤄봅시다.
- kaggle에서 데이터를 예측하다 보면, 에러가 아주 많이 발생합니다. 그 이유는, kaggle에서 제공되는 데이터들에 빈 공간이 너무 많기 때문이죠. 그냥 알아서! 빈 공간은 다 제외하고 주면 안됩니까! 라는 생각이 들지만, 몇 칸이 비어 있다고 해서, 나머지도 다 무시해서는 안되죠.
- 아무튼, 여기서는 missing value를 처리하는 방법을 정리해봅니다.
fill numerical missing values
- numerical 값들에 대해서, missing value를 채울 때는 보통 전체 데이터에 대해서 평균을 넣어주는 경우가 제일 많습니다.
- 하지만, 만약 categorical value별로 평균이 다르다면, 해당 instance가 속한 class를 고려해서 값을 추정해주는 것이 좋겠죠.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.concat([
pd.DataFrame({'v':np.random.normal(i*20, 2, num),'c':[chr(ord('A')+i) for j in range(0, num)]})
for i, num in enumerate([500, 300, 200])]).reset_index(drop=True)
plt.figure(figsize=(12, 4))
plt.scatter(range(0, len(df)), df['v'],
c= df['c'].apply(lambda x: ord(x)),
cmap=plt.cm.rainbow,
alpha=0.5)
plt.title("none na value", fontsize='x-large')
plt.savefig('../../assets/images/markdown_img/180605_1731_missing_numeric_v_non_na_value.svg')
plt.show()
## drop somethings
df_nan = df.copy()
df_nan['v'] =[ np.nan if abs(np.random.normal(0, 1)) > 1.0 else x for x in df['v']]
## 그냥 평균으로 일괄적으로 fillna를 해주면 아래 그림처럼 문제가 발생할 수 있음.
df_nan_fillna_mean = df_nan.fillna(df_nan.mean())
plt.figure(figsize=(12, 4))
plt.scatter(range(0, len(df_nan)), df_nan_fillna_mean['v'],
c= df_nan_fillna_mean['c'].apply(lambda x: ord(x)),
cmap=plt.cm.rainbow,
alpha=0.5)
plt.title("fillna by all mean", fontsize='x-large')
plt.savefig('../../assets/images/markdown_img/180605_1731_missing_numeric_v_fillna_all_mean.svg')
plt.show()
"""
- 그래서 class를 고려해서 평균을 따로 내서 넣어주는 것이 좋다.
- 아래처럼 그룹별로 평균을 낸 값으로 따로따로 그룹별로 dataframe을 계산 한 다음, 값을 넣어준다.
"""
df_nan_with_group_mean = pd.concat(
[g[1].fillna(g[1].mean()) for g in df_nan.groupby('c')]
)
plt.figure(figsize=(12, 4))
plt.scatter(range(0, len(df_nan_with_group_mean)), df_nan_with_group_mean['v'],
c=df_nan_with_group_mean['c'].apply(lambda x: ord(x)),
cmap=plt.cm.rainbow,
alpha=0.5)
plt.title("fillna by group mean", fontsize='x-large')
plt.savefig('../../assets/images/markdown_img/180605_1731_missing_numeric_v_fillna_group_mean.svg')
plt.show()
- 아래 그림에서처럼 전체 평균으로 채워 넣을 경우 슬픈 결과가 나올 수 있습니다.
fillin categorical values
- 이 경우는 남아 있는 numericl value를 사용해서 거리를 비교하고, 가장 가까운 사람의 categorical value를 넣어주는 것이 제일 좋습니다.
- 하지만 직접 코딩은 하지 않았습니다. 매우 귀찮아요.
"""
- 그럼 반대로, categorical value가 na일 경우
"""
df = pd.concat([
pd.DataFrame({'v':np.random.normal(i*20, 2, num),'c':[chr(ord('A')+i) for j in range(0, num)]})
for i, num in enumerate([500, 300, 200])]).reset_index(drop=True)
plt.figure(figsize=(12, 4))
plt.scatter(range(0, len(df)), df['v'],
c= df['c'].apply(lambda x: ord(x)),
cmap=plt.cm.rainbow,
alpha=0.5)
plt.title("none na value", fontsize='x-large')
plt.savefig('../../assets/images/markdown_img/180605_1734_fill_categorical_v.svg')
plt.show()
## drop somethings
df_nan = df.copy()
df_nan['c'] =[ np.nan if abs(np.random.normal(0, 1)) > 1.0 else x for x in df['c']]
"""
그냥 빈번한 것들을 random sampling해서 넣어줄경우?
"""
df_nan_with_random = df_nan.copy()
df_nan_with_random['c'] = [ np.random.choice(df_nan['c'].dropna()) if pd.isnull(x) else x for x in df_nan['c']]
plt.figure(figsize=(12, 4))
plt.scatter(range(0, len(df)), df_nan_with_random['v'],
c= df_nan_with_random['c'].apply(lambda x: ord(x)),
cmap=plt.cm.rainbow,
alpha=0.5)
plt.title("random sampling", fontsize='x-large')
plt.savefig('../../assets/images/markdown_img/180605_1734_fill_categorical_v_fill_random.svg')
plt.show()
"""
- cluster 별로 평균을 내고, 그 중에서 가장 가까운 class를 이용해서 missing value를 채움
"""
wrap-up
- missing value는 나중에 채웁시다. 아 이거 너무 빡시고 귀찮은 일이에요.
- 일단 dropna로 치워버리고, 나중에 한번에 처리하는게 훨씬 좋을 것 같아요. 극혐극혐
댓글남기기