Kaggle House Prices ① ～ 特徴量エンジニアリング ～

以下の Kaggle のコンペの特徴量エンジニアリングとなります。
[House Prices: Advanced Regression Techniques](https://www.kaggle.com/c/house-prices-advanced-regression-techniques)

以下を参考にしています。
[kaggleの住宅価格予測問題（House Prices）を解いてみる](https://medium-s.jp/kaggle-house-prices/)
[kaggle：House Price チュートリアル(住宅価格の予測)](https://data-bunseki.com/2019/08/15/kaggle%EF%BC%9Ahouse-price-%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB%E4%BD%8F%E5%AE%85%E4%BE%A1%E6%A0%BC%E3%81%AE%E4%BA%88%E6%B8%AC/)

## ライブラリの読み込み
```py
import numpy as np
import pandas as pd
from sklearn.externals import joblib
```

## データの読み込み
```py
train = pd.read_csv('train.csv')
test_x = pd.read_csv('test.csv')
```

## 外れ値を除外
```py
#物件の広さを合計した変数を作成
train["TotalSF"] = train["1stFlrSF"] + train["2ndFlrSF"] + train["TotalBsmtSF"]
test_x["TotalSF"] = test_x["1stFlrSF"] + test_x["2ndFlrSF"] + test_x["TotalBsmtSF"]
#外れ値を除外する
train = train.drop(train[(train['TotalSF']>7500) & (train['SalePrice']<300000)].index)
train = train.drop(train[(train['YearBuilt']<2000) & (train['SalePrice']>600000)].index)
train = train.drop(train[(train['OverallQual']<5) & (train['SalePrice']>200000)].index)
train = train.drop(train[(train['OverallQual']<10) & (train['SalePrice']>500000)].index)
```

## 学習データを目的変数とそれ以外に分ける
```py
train_x = train.drop('SalePrice',axis=1)
train_y = train["SalePrice"]
```

## 学習データとテストデータを統合
```
all_data = pd.concat([train_x,test_x],axis=0,sort=True)
```

## IDのカラムは不必要なので別の変数に格納
```py
train_ID = train_x['Id']
test_ID = test_x['Id']

all_data.drop("Id", axis = 1, inplace = True)
```

## 欠損値対応
```py
# 欠損値があるカラムをリスト化
na_col_list = all_data.isnull().sum()[all_data.isnull().sum()>0].index.tolist()

# 隣接した道路の長さ（LotFrontage）の欠損値の補完
all_data['LotFrontage'] = all_data.groupby('Neighborhood')['LotFrontage'].transform(lambda x: x.fillna(x.median()))

# 欠損値が存在するかつfloat型のリストを作成
float_list = all_data[na_col_list].dtypes[all_data[na_col_list].dtypes == "float64"].index.tolist()

# 欠損値が存在するかつobject型のリストを作成
obj_list = all_data[na_col_list].dtypes[all_data[na_col_list].dtypes == "object"].index.tolist()

# float型の場合は欠損値を0で置換
all_data[float_list] = all_data[float_list].fillna(0)

# object型の場合は欠損値を"None"で置換
all_data[obj_list] = all_data[obj_list].fillna("None")
```

## 数値変数をカテゴリ変数に変換
```py
all_data['MSSubClass'] = all_data['MSSubClass'].apply(str)
all_data['YrSold'] = all_data['YrSold'].astype(str)
all_data['MoSold'] = all_data['MoSold'].astype(str)
```

## 新たな特徴量の追加
```py
# 物件の広さを合計した変数を作成
all_data["TotalSF"] = all_data["1stFlrSF"] + all_data["2ndFlrSF"] + all_data["TotalBsmtSF"]

# 特徴量に1部屋あたりの面積を追加
all_data["FeetPerRoom"] =  all_data["TotalSF"]/all_data["TotRmsAbvGrd"]

# 建築した年とリフォームした年の合計
all_data['YearBuiltAndRemod']=all_data['YearBuilt']+all_data['YearRemodAdd']

# バスルームの合計面積
all_data['Total_Bathrooms'] = (all_data['FullBath'] + (0.5 * all_data['HalfBath']) +
                               all_data['BsmtFullBath'] + (0.5 * all_data['BsmtHalfBath']))

# 縁側の合計面積
all_data['Total_porch_sf'] = (all_data['OpenPorchSF'] + all_data['3SsnPorch'] +
                              all_data['EnclosedPorch'] + all_data['ScreenPorch'] +
                              all_data['WoodDeckSF'])

# プールの有無
all_data['haspool'] = all_data['PoolArea'].apply(lambda x: 1 if x > 0 else 0)

# 2階の有無
all_data['has2ndfloor'] = all_data['2ndFlrSF'].apply(lambda x: 1 if x > 0 else 0)

# ガレージの有無
all_data['hasgarage'] = all_data['GarageArea'].apply(lambda x: 1 if x > 0 else 0)

# 地下室の有無
all_data['hasbsmt'] = all_data['TotalBsmtSF'].apply(lambda x: 1 if x > 0 else 0)

# 暖炉の有無
all_data['hasfireplace'] = all_data['Fireplaces'].apply(lambda x: 1 if x > 0 else 0)
```

## カテゴリ変数に one-hot-encoding を行う
```py
# カテゴリ変数となっているカラムを取り出す
cal_list = all_data.dtypes[all_data.dtypes=="object"].index.tolist()

# カテゴリ変数をget_dummiesによるone-hot-encodingを行う
all_data = pd.get_dummies(all_data,columns=cal_list)
```

## 学習データとテストデータに再分割
```py
train_x = all_data.iloc[:train_x.shape[0],:].reset_index(drop=True)
test_x = all_data.iloc[train_x.shape[0]:,:].reset_index(drop=True)
```

## 特徴量を保存
```py
joblib.dump(train_x, 'train_x.pkl')
joblib.dump(test_x, 'test_x.pkl')
joblib.dump(train_y, 'train_y.pkl')
```