본문 바로가기

AI

[Kaggle] Melbourne 집값 예측하기 - 2 Missing Values

데이터 전처리를 거의 하지 않고 집값을 예측했던 모델을 점점 발전시켜보려고 한다

 

데이터가 모든 행마다 값이 다 차있으면 좋겠지만 현실에서 실제 데이터는 몇몇 특징이 비어있는 경우가 대부분일것이다

이때 비어있는 데이터를 어떻게 처리하는게 좋을지 알아보았다

 

1
2
3
4
5
6
7
8
9
10
11
# save filepath to variable for easier access
melbourne_file_path = '../input/melbourne-housing-snapshot/melb_data.csv'
# read the data and store data in DataFrame titled melbourne_data
melbourne_data = pd.read_csv(melbourne_file_path) 
 
= melbourne_data.drop('Price',axis=1).select_dtypes(exclude=['object'])
= melbourne_data.Price
 
from sklearn.model_selection import train_test_split
 
X_train,X_valid,y_train,y_valid = train_test_split(X,y,train_size = 0.8, test_size = 0.2, random_state=0)
cs

 

데이터의 numeric한 행만 사용하였다

type이 object인 행들은 버린 후 학습용 데이터 80프로 검증용 데이터 20프로로 나누어주었다

 

세가지의 방법으로 비어있는 데이터가 있는 데이터셋을 처리해보았다

이때 어떤 방법이 좋은지 비교하기위해 mae 를 계산해주었다

mae 계산은 편하게 하기 위해 함수화 시켜서 얻어주었다

 

1
2
3
4
5
6
7
8
9
from sklearn.metrics import mean_absolute_error
from sklearn.ensemble import RandomForestRegressor
 
def get_mae(train_X, val_X, train_y, val_y):
    model = RandomForestRegressor(n_estimators=10,random_state=0)
    model.fit(train_X, train_y)
    preds_val = model.predict(val_X)
    mae = mean_absolute_error(val_y, preds_val)
    return(mae)
cs

 

RandomForestRegressor를 사용해주었고

tree의 개수인 n_estimators는 10개로 지정해주었다

fit으로 train 후 predict로 예측을 해주고 mae를 구하여 return 해주었다

이제 각 방법에서의 mae를 비교하여 어떤 모델이 예측을 잘 하는지 비교해 볼 수 있다

 

1. Drop Columns with Missing Values

 

가장 간단한 방법이다

비어있는 데이터가 있는 열 자체를 버리는 것

isnull이 하나라도 있는 행을 X_train에서 골라 cols_with_missing에 저장하고

그 행들을 제거한 새로운 X_train과 X_valid를 만들어준다

 

이 때 mae는 183550.22137772635이 나왔다

 

1
2
3
4
5
6
7
8
9
10
# Get names of columns with missing values
cols_with_missing = [col for col in X_train.columns
                     if X_train[col].isnull().any()]
 
# Drop columns in training and validation data
reduced_X_train = X_train.drop(cols_with_missing, axis=1)
reduced_X_valid = X_valid.drop(cols_with_missing, axis=1)
 
print("MAE from Approach 1 (Drop columns with missing values):")
print(get_mae(reduced_X_train, reduced_X_valid, y_train, y_valid))
cs

 

2. Imputation

 

비어있는 데이터의 위치를 다른 데이터들을 이용해 채워주는 방법이다

사이킷런의 simple imputer를 사용하였다

SimpleImputer를 선언할 때 strategy 인자로 비어있는 데이터를 어떻게 채울 지 정할 수 있다

mean,median,most_frequent,constant를 사용할 수 있다

디폴트는 평균값을 사용한다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
from sklearn.impute import SimpleImputer
 
# Imputation
my_imputer = SimpleImputer()
imputed_X_train = pd.DataFrame(my_imputer.fit_transform(X_train))
imputed_X_valid = pd.DataFrame(my_imputer.transform(X_valid))
 
# Imputation removed column names; put them back
imputed_X_train.columns = X_train.columns
imputed_X_valid.columns = X_valid.columns
 
print("MAE from Approach 2 (Imputation):")
print(get_mae(imputed_X_train, imputed_X_valid, y_train, y_valid))
cs

 

평균값으로 빈 데이터를 채워주는 imputer를 만들어 사용해보았다

만들어진 imputer를 fit_transfrom, transform 함수를 사용하여 새로운 데이터 셋을 만들어주었다

예시코드에서는 사이킷런 imputer의 fit_transform, transform의 차이를 제대로 알려주지 않아서 따로 찾아보았다

 

사이킷런의 모든 transform의 fit 함수는 인자로 들어온 데이터에 맞게 데이터를 처리하기 위한 값들을 세팅해준다고 한다

예를 들어 평균값을 0으로 바꾸어주기 위한 transformation에서는  𝑥′ = (𝑥 − 𝜇) / 𝜎 과정을 수행하기 위해 𝜇, 𝜎 값이 필요한데 이 값을 정해주는 함수인 것이다

transform은 정해진 규칙에 따라 데이터를 변경해준다

fit_transform은 이 둘을 합쳐놓은 함수이다

이렇게 fit 과정과 transform 과정을 나누어준 것은 training set 마다 같은 방법으로 변화시켜주어야 하기 때문이다

train set에 의해 정해진 parameter로 cross validation set과 test set도 빈 값들을 채워주어야 한다

 

mae를 계산해보니 178166.46269899711으로 column을 삭제한 것 보다는 높은 정확도를 보였다

 

3. An Extension to Imputation

 

원래 비어있던 값을 임의로 채워넣는 과정에서 변화가 있었을 수 있다

비어있던 데이터들만의 다른 특성이 있었다면 그 값을 임의로 채워넣었다면 error가 크게 나올 것 이다

마지막 방법은 어떤 feature를 임의로 채워넣었는지 아닌지 여부 또한 training에 사용하는 것이다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Make copy to avoid changing original data (when imputing)
X_train_plus = X_train.copy()
X_valid_plus = X_valid.copy()
 
# Make new columns indicating what will be imputed
for col in cols_with_missing:
    X_train_plus[col + '_was_missing'= X_train_plus[col].isnull()
    X_valid_plus[col + '_was_missing'= X_valid_plus[col].isnull()
 
# Imputation
my_imputer = SimpleImputer()
imputed_X_train_plus = pd.DataFrame(my_imputer.fit_transform(X_train_plus))
imputed_X_valid_plus = pd.DataFrame(my_imputer.transform(X_valid_plus))
 
# Imputation removed column names; put them back
imputed_X_train_plus.columns = X_train_plus.columns
imputed_X_valid_plus.columns = X_valid_plus.columns
 
print("MAE from Approach 3 (An Extension to Imputation):")
print(get_mae(imputed_X_train_plus, imputed_X_valid_plus, y_train, y_valid))
cs

 

기존의 데이터셋에 어떤 행이 빈 데이터를 가지고 있는지를 체크하는 행을 추가시켜준다

원래 비어있었다면 True, 값을 가지고 있었다면 False를 가지는 행이 추가되었다

 

이제 이 데이터셋을 이전과 똑같이 imputer를 사용하여 Nan을 없애주고 mae를 구해보았다

178927.503183954이라는 mean absolute error를 얻을 수 있었다

더 좋은 결과가 나올 줄 알았지만 꼭 그렇지는 않았다