Kaggle「HousePrices」

# はじめに
東大HAITSというデータサイエンスを勉強する団体の活動で、kaggleというデータサイエンスコンペの「HousePrices」というコンペに挑戦しました。まだ、データサイエンスを勉強し始めて１か月ちょっとですので、基本的なことしかしていません。
#データの観察
### ライブラリのインポート
```python
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
%matplotlib inline
from scipy.stats import skew
from sklearn.linear_model import Lasso
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
```
###データの読み込み
```python
train = pd.read_csv("train.csv")
```
### データ数の確認
```python
print(train.shape)
```
train　(1460, 81)
変数の数が多く、変数選択が難しいと思う。色々試したが、いらない変数を落としていくほうがいい結果を得られたので、今回はそういった方針で進めていく。
#欠損値処理
### 欠損値の確認

```python
train.isnull().sum()[train.isnull().sum()>0].sort_values(ascending=False)
```

 - PoolQC 1453
 - MiscFeature 1406
 - Alley 1369
 - Fence 1179
 - FireplaceQu 690
 - LotFrontage 259
 - GarageYrBlt 81
 - GarageType 81
 - GarageFinish 81
 - GarageQual 81
 - GarageCond 81
 - BsmtFinType2 38
 - BsmtExposure 38
 - BsmtFinType1 37
 - BsmtCond 37
 - BsmtQual 37
 - MasVnrArea 8
 - MasVnrType 8
 - Electrical 1
 
欠損値の多い列は削除することにした。

```python
train = train.drop(columns=["PoolQC","MiscFeature","Alley","Fence" ,"FireplaceQu" ,"LotFrontage"])
```

#####残りの欠損値処理
今回は変数の数が多いこともあり、便宜上、欠損値処理として**One Hot Encoding**、補完処理は**平均値**で補う。
他にも**LabelEncoder**などいろいろなやり方がある。変数によって使い分けることで精度が高くなると思う。

```python
train = pd.get_dummies(train)
train = train.fillna(train.mean())
```
#新たな変数の設計

住宅を選ぶときはまず、土地の面積と築年数を調べる人が多いだろう。これをあらわす変数が欲しいという流れは至って自然だろう。また、このデータは2011年のものであると調べると分かるので、2011年における築年数とする。（http://jse.amstat.org/v19n3/decock.pdf ）

```python
train["TotalSF"] = train["TotalBsmtSF"] + train["1stFlrSF"] + train["2ndFlrSF"] + train['GarageArea']
train['YearBuilt'] = 2011 - train['YearBuilt']
```
######新たな変数を作るときに使った変数は取り除く。

```python
train.drop(['1stFlrSF','GarageArea',"TotalBsmtSF","2ndFlrSF"], axis=1, inplace=True)
```

#可視化
####相関係数の大きい順に並べる。

```python
np.abs(train.corr()["SalePrice"]).sort_values(ascending=False).head(10)
```

['SalePrice', 'TotalSF', 'OverallQual', 'GrLivArea', 'GarageCars', 'ExterQual_TA', 'FullBath', 'BsmtQual_Ex', 'YearBuilt','KitchenQual_TA']
##Heatmap
######相関係数の大きいもの10個を選んでお互いの相関係数を表示する。

```python
plt.figure(figsize=(12, 9))
sns.heatmap(train.loc[:,['SalePrice', 'OverallQual', 'TotalSF', 'GrLivArea', 'GarageCars',
 'ExterQual_TA', 'FullBath', 'BsmtQual_Ex', 'YearBuilt',
 'KitchenQual_TA']].corr(), annot=True, square=True, fmt='.2f')
plt.show()
```

![figure.png](https://qiita-image-store.s3.amazonaws.com/0/209205/ad84b242-d650-1bd8-01dd-94fad8a29459.png)
##Pairplot

```python
sns.pairplot(train.loc[:,[ "TotalSF", "OverallQual", "GrLivArea", 'YearBuilt',"SalePrice"]])
```
![figure2.png](https://qiita-image-store.s3.amazonaws.com/0/209205/eaa99da4-ca04-202e-b99c-bf35c949385c.png)

##外れ値の処理
上のpairplot図で外れ値になりそうなものがあることが分かるだろう。'GrLivArea'と"SalePrice"のjointlplot図で確認しよう。

```python
sns.jointplot('GrLivArea',"SalePrice",data= train)
```

![figure3.png](https://qiita-image-store.s3.amazonaws.com/0/209205/ab5ea746-f25d-ea3d-dc3d-46345e571296.png)
右下の2点はおそらく外れ値であるので取り除く。
######しっかり取り除けたか確認しよう。

```python
train = train[~((train['GrLivArea'] > 4000) & (train['SalePrice'] < 300000))]
```

![figure4.png](https://qiita-image-store.s3.amazonaws.com/0/209205/b4e4e403-814a-2698-39f2-4c59237c8ffb.png)
##"OverallQual"と"SalePrice"

```python
sns.jointplot("OverallQual","SalePrice",data= train)
```

![figure5.png](https://qiita-image-store.s3.amazonaws.com/0/209205/b28609e5-24fc-93b8-c0e8-cc4f2ec8fdac.png)

このグラフを見る限り、2次関数のような振る舞いをするようにも思える。そこで、"OverallQual"については２次まで検討する。

```python
train["OverallQual_2"]=train["OverallQual"]**2

```

##"SalePrice"
SalePriceについて観察する。

```python
sns.distplot(train["SalePrice"])
plt.show()
```

![figure6.png](https://qiita-image-store.s3.amazonaws.com/0/209205/94c05acd-6261-bf2c-370b-8ffc3b1534a5.png)
グラフが左へ歪んでいるのが分かるだろう。そこで、**対数変換**を用いる。
#対数変換
######対数変換をするメリット
小さな数を大きな数で,大きな数を小さな数で扱える.桁の大きい数のスケールを小さく，または桁の小さい数のスケールを大きくできると，感覚的に数を扱いやすくなる。（**正規分布**に近づく）この考え方は，マグニチュード，pHなど比較するために利用されている。
#####全体として対数変換を行う。

```python
train = np.log1p(train)
```

######対数変換後のSalePrice
![figure7.png](https://qiita-image-store.s3.amazonaws.com/0/209205/6c01e2ac-8f2e-2191-c4aa-cecfb6e5a6cf.png)
正規分布に近づいているのが分かる。
##対数変換後の観察

```python
plt.figure(figsize=(12, 9))
sns.heatmap(train.loc[:,['SalePrice', 'OverallQual',OverallQual_2' 'TotalSF', 'GrLivArea', 'GarageCars',
 'ExterQual_TA', 'FullBath', 'BsmtQual_Ex', 'YearBuilt',
 'KitchenQual_TA']].corr(), annot=True, square=True, fmt='.2f')
plt.show()
```

![figure8.png](https://qiita-image-store.s3.amazonaws.com/0/209205/cdb14b0c-6dd7-5463-70f1-d6b3dad544c1.png)
グラフを見るとSalePriceが11あたりより小さい部分が気になる。住宅価格が低いときのデータが少ないことや幽霊物件の可能性も考えて、今回は取り除こうと思う。

```python
train = train[~(train['SalePrice'] < 11.1)]
```

```python
plt.figure(figsize=(12, 9))
sns.heatmap(train.loc[:,['SalePrice', 'OverallQual',OverallQual_2' 'TotalSF', 'GrLivArea', 'GarageCars',
 'ExterQual_TA', 'FullBath', 'BsmtQual_Ex', 'YearBuilt',
 'KitchenQual_TA']].corr(), annot=True, square=True, fmt='.2f')
plt.show()
```

![figure9.png](https://qiita-image-store.s3.amazonaws.com/0/209205/be0a45c2-dbfa-7631-35ae-0b1842e9a0bb.png)
#学習
色々、試したが今回はLasso回帰が一番良い結果を得られた。

```python
X = train.loc[:,train.columns != "SalePrice"]
y = train.loc[:, ['SalePrice']].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 0)
las = Lasso(alpha=0.0005)
las.fit(X_train, y_train)
print("ラッソ回帰でのRMSE：",np.sqrt(mean_squared_error(las.predict(X_test), y_test)))
```
#結果
ラッソ回帰でのRMSE: 0.10114175427614815
#Kaggleでの評価
public score : 0.11833
　　　順位：　228/4649（上位4.9パーセント）
#反省
まだまだ、改善すべきことがたくさんあると思う。とくに欠損値の処理や変数の設計をもっと厳密にする必要があると思う。ただ、データサイエンスとはどういうものなのかを知れたのはとても良かったと思う。