【Python3】機械学習を使ってデータ分析をやってみよう！（回帰）

# 対象
- AIに興味がある人
- 興味があるけど何からすれば良いか分からない人
- AIで何ができるのか知りたい人


# 前提
- Googleアカウントを持っている
- Google Driveの基本的な使い方を知っている
- Python3の基本的な使い方を知っている
- 機械学習の理論については扱わない

機械学習の概要に関しては以下を参照
> [一から始める機械学習（機械学習概要） - Qiita](https://qiita.com/taki_tflare/items/42a40119d3d8e622edd2)


# ゴール
- テーブルデータの目的の列の値をある程度の精度で予測できる
- データ分析に必要な専門用語が少し分かる
- データをグラフで表示できる

![ランダムフォレスト02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/4b4aa6e8-73f2-eeb0-6695-670f9aefce98.png)

# 前知識
予測するデータの種類によって使うモデルが変わる

- 分類
0か1の2種類のラベルを予測すること
例）ウイルス検査の陽性・陰性、ある顧客がサービスを解約するか否か

- 回帰
数値を予測すること
例）売上、来客数

今回扱うのは回帰である

# 流れ
1. Google Colaboratoryの準備
 - 初期画面
 - ランタイムの接続
 - 画面の説明
 - セルの追加
2. データの読み込み
3. データの確認
  - 先頭表示（head）
  - カラムの説明
  - 詳細情報の確認（describe）
  - 各カラムの欠損値と型確認（info）
  - ヒストグラム（hist）
  - 相関の確認（scatter_matrix）
  - 場所ごとの住宅価格の中央値を確認（Basemap）
  - ここまでで分かったこと - part1
4. モデルの学習と予測 - part1
  - データを学習用・検証用・テスト用に分割
  - 何故検証用データを用意するのか？
  - 予測結果の精度を描画する関数を定義
  - 線形回帰の学習と予測精度の可視化（前処理なし）
  - XGBoostの学習と予測精度の可視化（前処理なし）
  - ランダムフォレストの学習と予想精度の可視化（前処理なし）
  - ここまでで分かったこと - part2
5. 前処理
  - 外れ値の確認
  - 外れ値の削除
  - all_dataをtrainとtestに分割
6. モデルの学習と予測 - part2
  - データを学習用・検証用・テスト用に分割
  - 標準化
  - 線形回帰の学習と予測精度の可視化（前処理あり）
  - - XGBoostの学習と予測精度の可視化（前処理あり）
  - ランダムフォレストの学習と予想精度の可視化（前処理あり）
7. まとめ
8. その他参考文献


# Google Colaboratoryの準備
1. Google Driveにアクセス
2. 作業用にフォルダを作成（今回はhandsonという名前のフォルダを作成）
3. 作成したフォルダに移動
4. 「右クリック」 => 「その他」 => 「Google Colaboratory」を選択


## 初期画面
以下のようになっているはずだ（一部省略）
![初期画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/3b59400f-4103-6866-6276-55271031183b.png)


## ランタイムの接続
左側のタブからsample_dataを開いて、`california_housing_{train/test}.csv`があることを確認できたらOK
![左側.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/cc7812d7-6cab-cdd1-c6fc-138d524527ec.png)


## 画面の説明
![セルの説明.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/1ba312ad-8936-c9ce-28ac-16053faa207d.png)
<font color='red'>赤枠</font>：テキストセル（マークダウン記法）
<font color='blue'>青枠</font>：コードセル（python）
<font color='green'>緑枠</font>：出力結果

セルの実行はセルを選択した状態で「Shift」+「Enter」かセル左側のスタートアイコンで実行できる
実行はセルごとに行われ、変数の値はセルを移動しても保持される
コードセルの実行した順番は<font color='blue'>青枠</font>の左側の数字で分かる
コードセルの最後の変数が出力されるため`print(hi)`を記述する必要がない（超便利！）


## セルの追加
以下の画像左上の「+ コード」、「+ テキスト」やセル中央にカーソルを合わせると表示されるボタンで追加できる
![コードorテキストの表示.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/6de38e17-ce5d-6b81-1430-72a09787f615.png)

詳細な使い方は以下を参照
> - [Google Colabの知っておくべき使い方 – Google Colaboratoryのメリット・デメリットや基本操作のまとめ](https://www.codexa.net/how-to-use-google-colaboratory/)
- [Google Colaboratoryの使い方【完全マニュアル】](https://obgynai.com/google-colaboratory/)
- [Google Colabの使い方まとめ - Qiita](https://qiita.com/shoji9x9/items/0ff0f6f603df18d631ab)
- [Colaboratoryショートカット備忘録 - Qiita](https://qiita.com/t_m_t_m/items/ab20e8c4459c4952ab7d)

ここからは適宜セルを追加して実行しよう


# データの読み込み
今回はサンプルデータのcalifornia housingデータを使う
Colaboratoryにはあらかじめサンプルデータが用意されている

```python
import pandas as pd
pd.options.display.precision = 3

train = pd.read_csv('sample_data/california_housing_train.csv')
test = pd.read_csv('sample_data/california_housing_test.csv')
```
pandasとは？ - [wiki](https://ja.wikipedia.org/wiki/Pandas)
> pandasは、プログラミング言語Pythonにおいて、データ解析を支援する機能を提供するライブラリである。特に、数表および時系列データを操作するためのデータ構造と演算を提供する

`pd.options.display.precision`で小数点以下何桁を表示するか設定している（今回は説明の都合上、小数点以下3桁としている）
`read_csv`でcsvファイルを読み込むことができる

# データの確認
ここからは、データを眺めてみます

## 先頭表示（head）
```python
train.head()
```
![train_head.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/0dd59814-f579-bfe0-6be4-a8cfbfffbe5f.png)
`head`で先頭5行までのテーブルデータを確認できる（引数に値を入れるとその数まで表示される）

`test`も確認してみよう！

## 各カラムの説明

|カラム名|説明|
|----|----|
|longitude|経度|
|latitude|緯度|
|housing_median_age|ブロックの築年数の中央値|
|total_rooms|ブロック内の部屋の総数|
|total_bedrooms|ブロック内の寝室の総数|
|population|ブロック内に住む人の総数|
|households|1ブロックあたりの世帯数|
|median_income|ブロック内の世帯収入の中央値 [万ドル]|
|median_house_value|ブロック内の住宅価格の中央値 [ドル]|

各カラムの詳細は以下
> [California Housing Data Set Description](https://developers.google.com/machine-learning/crash-course/california-housing-data-description)

今回予測するカラムは`median_house_value`でこれを**目的変数**と呼ぶ
それ以外のカラムは予測に必要なデータでこれを**説明変数**と呼ぶ


## 詳細情報の確認（describe）
```python
train.describe()
```
![train_describe.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/68c817f3-60c9-bd7b-31c1-785fb115e866.png)

`describe`で各列の以下の情報が表示される

|名前|意味|
|----|----|
|count|行数|
|mean|平均値|
|std|標準偏差|
|min|最小値|
|25%|第一四分位数|
|50%|中央値|
|75%|第三四分位数|
|max|最大値|

`test`も確認してみよう！

## 各カラムの欠損値と型確認（info）
```python
train.info()
```
![train_info.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/bfe92a3d-773d-d728-46c0-7ed5d0047cc5.png)
`Non-Null Count`の各項目の値が`describe`で確認した`count`と同じ17000であるため、欠損値はないことが分かる
欠損値がある場合は、何かの値で補完したり、その行を削除して学習データに使わないなどの処理が必要となる

`test`も確認してみよう！

## ヒストグラム（hist）
グラフ表示に必要なライブラリのインストール

```python
import matplotlib.pyplot as plt
%matplotlib inline
```

ヒストグラムの表示

```python
train.hist(bins=50, figsize=(10, 10))
```

![train_hist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/03e448fb-d469-6d86-e215-0f9e1267b71c.png)

matplotlibとは？ - [wiki](https://ja.wikipedia.org/wiki/Matplotlib)
> Matplotlibは、プログラミング言語Pythonおよびその科学計算用ライブラリNumPyのためのグラフ描画ライブラリ

- `%matplotlib inline`はおまじないのようなもの
- `hist`でヒストグラム表示
- `bins`は棒の数
- `figsize`でグラフサイズ変更（お好みでどうぞ）

`test`も確認してみよう！

## 相関の確認（scatter_matrix）
```python
pd.plotting.scatter_matrix(train, diagonal='kde', figsize=(10, 10))
```
![train_scatterMatrix.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/c1daeed0-9608-bc3c-2e43-c4a201285647.png)
`diagonal='kde'`でカーネル密度推定を選択

参考文献
> - [pandas.plotting.scatter_matrix](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.plotting.scatter_matrix.html)
- [scatter_matrix（スカッター行列）について - Qiita](https://qiita.com/mitsumizo/items/efddc80f166e900f97ef)
- [matplotlib (+ pandas) によるデータ可視化の方法 (5) - Qiita](https://qiita.com/ynakayama/items/2ec380ab1176e4569ebe)

`test`も確認してみよう！

## 場所ごとの住宅価格の中央値を確認（Basemap）
Basemapのインストール

```bash
!apt-get install libgeos-3.5.0
!apt-get install libgeos-dev
!pip install https://github.com/matplotlib/basemap/archive/master.zip
```
以下が表示されたら、下のボタンからランタイムを再起動する
![basemap_restart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/a5209d9b-6472-5b75-46bf-78097d4fa013.png)
再起動したら、Basemapのインストールを含めて上から実行していく
`Successfully built basemap`が表示されたらOK

Basemapのインストールと地図上にプロットを表示する関数を定義

```python
from mpl_toolkits.basemap import Basemap

def basemap(x, y, target):
  fig = plt.figure(dpi=300)
  xyrange = 0.5
  m = Basemap(projection="cyl", resolution="i", llcrnrlat=y.min()-xyrange, urcrnrlat=y.max()+xyrange, llcrnrlon=x.min()-xyrange, urcrnrlon=x.max()+xyrange)
  m.drawparallels(np.arange(-90, 90, 0.5), labels=[True, False, True, False],linewidth=0.0, fontsize=4)
  m.drawmeridians(np.arange(0, 360, 0.5), labels=[True, False, False, True],linewidth=0.0, rotation=45, fontsize=4)
  m.drawcoastlines(color='k')
  m.arcgisimage(service='World_Street_Map', verbose=True, xpixels=1000, dpi=300)
  plt.scatter(x, y, c=target, s=5, cmap=plt.get_cmap('jet'), alpha=0.4, linewidths=0)
  plt.colorbar()
```
カリフォルニア周辺にデータをプロット

```python
basemap(train['longitude'], train['latitude'], train['median_house_value'])
```
![train_basemap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/599c86f9-1a56-a7b3-9095-cb8ed80289a4.png)
参考文献
> - [Basemapで位置情報を可視化する - Qiita](https://qiita.com/OSAKO/items/7eb3ebc6b32afdf80bc6)
- [Google Colabにbasemapをインストールして使用するには?](https://www.366service.com/jp/qa/1b1279a6f970bdfc7b6733f7e66ce700)
- [Basemap tutorial](https://basemaptutorial.readthedocs.io/en/latest/backgrounds.html)

`test`も確認してみよう！

## ここまでで分かったこと - part1
1. `train`と`test`のデータの分布がほとんど同じ（describeの各項目やヒストグラムがほとんど似てるため）
2. `housing_median_age`、`median_house_value`の最大値あたりが外れ値っぽい（ヒストグラムから）
3. `total_rooms`、`total_bedrooms`、`population`、`households`がそれぞれ相関関係にありそう（相関のグラフより）
4. 海沿い物件の住宅価格の中央値は高そうだ（Basemapより）

外れ値とは？ - [wiki](https://ja.wikipedia.org/wiki/%E5%A4%96%E3%82%8C%E5%80%A4)
> 外れ値（はずれち、英: outlier）は、統計学において、他の値から大きく外れた値のこと

これらを踏まえて、本来なら次に前処理を行う
しかし、**前処理の重要性を理解するため**に、敢えて行わず機械学習モデルの学習に取り組む


# モデルの学習と予測 - part1
前処理を行わず、学習を行なってみる
今回使うモデルは以下

- 線形回帰（線形モデル）
- XGBoost（決定木モデル）
- ランダムフォレスト（決定木モデル）

**線形モデルの特徴**

- 特徴量は数値
- 欠損値が扱えない
- 標準化が必要
- 単体では精度は高くなく、GBDTやニューラルネットに勝てることはほとんどない

**決定木モデルの特徴**

- 特徴量は数値
- 欠損値も扱える
- パラメータチューニングをしなくても精度が出やすい
- 不要な特徴量を追加しても精度が落ちにくい
- 特徴量をスケーリング（標準化や正規化）しなくて良い

ある程度の精度で予測したい場合は、決定木モデルの方が扱いやすくて簡単
今回は比較として、線形モデルも扱う
線形モデルには特徴量の標準化が必要だが、part1では、敢えて標準化を行わず、part2でどのくらい精度が変わるのか確認する

標準化とは？ - [データ科学便覧](https://data-science.gr.jp/theory/tbs_standardization.html)
> 統計学における標準化 (standardization) とは，与えられたデータを平均が0で分散が1のデータに変換する操作のことをいう．

## データを学習用・検証用・テスト用に分割
```python
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# 目的変数
obj_var = 'median_house_value'

# テスト用の説明変数
x_test = test.drop(obj_var, axis=1)
# テスト用の目的変数
y_test = test[obj_var]

# 学習用の説明変数
x = train.drop(obj_var, axis=1)
# 学習用の目的変数
y = train[obj_var]

# 学習用データを、学習用と検証用に分割
x_train, x_valid, y_train, y_valid = train_test_split(x, y, test_size=0.2, random_state=144, shuffle=True)
```
- `train_test_split`でデータを学習用と検証用に分割する
- `test_size=0.2`で学習用と検証用を8:2の割合で分割
- `random_state`は疑似乱数でこれを指定しないと、実行のたびに結果が変わってしまう

数字は自身のお好みの数字でどうぞ

- `shuffle=True`で分割をシャッフルする

指定しない（False）場合、データの先頭から8割が学習用、残り2割が検証用として分割される

- `mean_squared_error`は予測精度を確認するために後で使う

## なぜ検証用データを用意するのか？
学習用データとテスト用データのみで予測精度を評価した場合、テスト用データの予測に特化したモデルができてしまうため（過学習という）

例えば、ある年の1月から5月までのデータを使って天気を予測したい場合
テスト用のデータによる評価のみで予測精度を高める（過学習）と、その年の1月から5月までの天気は上手く予測できる
しかし、次の年の1月から5月の天気は前年とは異なり予測精度が悪くなる
これは、未知のデータに対して、予測できていないためである

検証用データを用意して、検証用とテスト用の2つのデータを同じくらいの精度で予測できるようにしておくと、未知のデータに対してある程度の精度を維持したまま予測することができる（過学習の防止）

過学習とは？ - [wiki](https://ja.wikipedia.org/wiki/%E9%81%8E%E5%89%B0%E9%81%A9%E5%90%88)
> 過剰適合（かじょうてきごう、英: overfitting）や過適合（かてきごう）や過学習（かがくしゅう、英: overtraining）とは、統計学や機械学習において、訓練データに対して学習されているが、未知データ（テストデータ）に対しては適合できていない、汎化できていない状態を指す。汎化能力の不足に起因する。

今回は、一番簡単なhold-out法を用いる
他にもクロスバリデーションやk-foldなど様々

## 予測結果の精度を描画する関数を定義
```python
def predict_visualizer(valid, valid_predict, test, test_predict, title):
  valid_array = np.array(valid)
  test_array = np.array(test)
  va_pred_array = np.array(valid_predict)
  ts_pred_array = np.array(test_predict)
  y_values = np.concatenate([valid_array, va_pred_array]).flatten()
  ymin, ymax = np.amin(y_values), np.amax(y_values)
  fig = plt.figure(figsize=(10, 10))
  plt.scatter(valid_array, va_pred_array, label='valid', color='aqua', alpha=0.4)
  plt.scatter(test_array, ts_pred_array, label='test', color='tomato', alpha=0.4)
  plt.plot([ymin, ymax], [ymin, ymax])
  plt.xlabel('test', fontsize=24)
  plt.ylabel('predict', fontsize=24)
  plt.title(f'{title}-Test-Predict Plot', fontsize=24)
  plt.tick_params(labelsize=16)
  plt.legend()
  plt.show()
```

## 線形回帰の学習と予測精度の可視化（前処理なし）
```python
from sklearn.linear_model import LinearRegression

lr = LinearRegression()
lr.fit(x_train, y_train)
y_pred = lr.predict(x_valid)
y_pred_test = lr.predict(x_test)
print('='*20)
print('LinearRegression')
print(f'valid_RMSE: {np.sqrt(mean_squared_error(y_valid, y_pred))}')
print(f'test_RMSE: {np.sqrt(mean_squared_error(y_test, y_pred_test))}')
predict_visualizer(y_valid, y_pred, y_test, y_pred_test, 'lr')
```
![線形回帰01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/63645a41-7468-dd69-b3dd-74f4ad2e1fc7.png)

- `fit`でモデルを学習させる
- `predict`で目的変数を予測する

今回は検証用とテスト用のデータ2つをそれぞれ予測する
予測精度を評価するために、今回はRMSE（Root Mean Squared Error）と呼ばれる平均平方2乗誤差を用いる
計算式は以下

---

$RMSE=\sqrt{\displaystyle\frac{1}{N}\sum_{i=1}^{n}(y_i-\hat{y_i})^2}$

$N$：予測対象データの総数
$y_i$：$i$番目の実際の値
$\hat{y_i}$：$i$番目の予測した値

---

`mean_sqared_error`で平均2乗誤差を求め、`np.sqrt`で平方根をとる
結果から、RMSEは約7万となった
このモデルで住宅価格の予測を行なった場合、平均7万ドルの誤差で予測できることを意味している

散布図の見方として、青い直線に点が近いほど精度の高い予測であることを表す
この結果を見ると、`test`が500000の時、上手く予測できていない
これは外れ値の影響を強く受けているためだと考えられる

同様にして、他のモデルも見てみよう

## XGBoostの学習と予測結果の可視化（前処理なし）
```python
import xgboost as XGB

xgb = XGB.XGBRegressor(random_state=144)
xgb.fit(x_train, y_train)
y_pred = xgb.predict(x_valid)
y_pred_test = xgb.predict(x_test)
print('='*20)
print('XGBRegressor')
print(f'valid_RMSE: {np.sqrt(mean_squared_error(y_valid, y_pred))}')
print(f'test_RMSE: {np.sqrt(mean_squared_error(y_test, y_pred_test))}')
predict_visualizer(y_valid, y_pred, y_test, y_pred_test, 'xgbr')
```
![XGBoost01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/d410577c-d834-dacc-27f5-73ad914b4fc8.png)
結果から、RMSEは約55000となった
線形回帰モデルよりも高い精度で予測できている
しかし、`test`が500000の時に上手く予測できていないことは同じである

## ランダムフォレストの学習と予測結果の可視化（前処理なし）
```python
from sklearn.ensemble import RandomForestRegressor

rfr = RandomForestRegressor(random_state=144, n_estimators=100)
rfr.fit(x_train, y_train)
y_pred = rfr.predict(x_valid)
y_pred_test = rfr.predict(x_test)
print('='*20)
print('RandomForestClassifier')
print(f'valid_RMSE: {np.sqrt(mean_squared_error(y_valid, y_pred))}')
print(f'test_RMSE: {np.sqrt(mean_squared_error(y_test, y_pred_test))}')
predict_visualizer(y_valid, y_pred, y_test, y_pred_test, 'rfr')
```
![ランダムフォレスト01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/79fc8e05-24b7-08cf-2150-2d0095c57b6a.png)
`n_estimators`で木の数を設定できる（今回は決め打ちで100）
結果から、RMSEは約49000となった
XGBoostよりも高い精度で予測できている
しかし、`test`が500000の時に上手く予測できていないことは同じである

## ここまでで分かったこと - part2

|モデル|検証用RMSE|テスト用RMSE|
|----|----:|----:|
|線形回帰|70139|69766|
|XGBoost|55100|55100|
|ランダムフォレスト|48458|49924|

1. ランダムフォレストが一番精度の高い予測を行えている
2. `test`が500000の時の予測はどのモデルも上手くできていない

「ここまでで分かったこと - part1」でも述べた、外れ値が悪さをしているようだと予想できる
ここからは、前処理によって外れ値による影響を解消する

# 前処理
前処理する前に全てのデータ（`train`と`test`）を一つにまとめる

```python
train_mid = train.copy()
test_mid = test.copy()

train_mid['train_test'] = 'train'
test_mid['train_test'] = 'test'

all_data = pd.concat([train_mid, test_mid]).reset_index(drop=True)
all_data.head()
```

- `copy()`で`train`と`test`のデータを汚さないようにする
- `train_test`カラムを追加
- `pd.concat`で複数のDataFrameを結合
- `reset_index`でインデックスをリセット
- `drop=True`で元のインデックスを削除（これをしないと元のインデックスも含まれてしまう）

## 外れ値の確認
「ここまでで分かったこと - part1」の項目2.
> `housing_median_age`、`median_house_value`の最大値あたりが外れ値っぽい（ヒストグラムから）

を具体的に確認する

```python
all_data['housing_median_age'].value_counts()
```
（結果一部省略）
![housing_median_age.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/4f6f078c-e341-1f23-2bcd-48b030f93ff2.png)
`value_counts()`でそれぞれの値の出現頻度を高い順に確認できる
結果から、最大値（describe参照）の52.0が最も多いことが分かる

`median_house_value`カラムも確認する

```python
all_data['median_house_value'].value_counts()
```
（結果一部省略）
![median_house_value.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/6e04d57c-b6cb-ea6c-2aca-b2afbf4074d4.png)
結果から、最大値の500001.0が最も多いことが分かる

2つの結果から、それぞれの最大値が外れ値であることが分かり、予測精度に悪影響を及ぼしていると考えられる

## 外れ値の削除
それぞれの最大値を削除する

```python
all_data = all_data.query(' housing_median_age < 52 and median_house_value < 500000 ').reset_index(drop=True)
```
`query`で条件に一致する行のみ抽出できる
抽出によってインデックスが飛び飛びになるので`reset_index`を忘れずに

`describe`や`hist`でどのように変わったか確認してみよう！

※KaggleやSIGNATEなどの分析コンペでは、testデータを削除してはいけない
分析コンペの場合、学習用データの外れ値のみ削除する

## all_dataをtrainとtestに分割
外れ値を削除する前処理が終わったので、`train`と`test`に分割

```python
train = all_data.query(" train_test == 'train' ").drop('train_test', axis=1)
test = all_data.query(" train_test == 'test' ").drop('train_test', axis=1)
```

# モデルの学習と予測 - part2
「モデルの学習と予測 - part1」とほとんど同じように進める

## データを学習用・検証用・テスト用に分割
part1の処理と同じ

```python
x_test = test.drop(obj_var, axis=1)
y_test = test[obj_var]

x = train.drop(obj_var, axis=1)
y = train[obj_var]

x_train, x_valid, y_train, y_valid = train_test_split(x, y, test_size=0.2, random_state=144, shuffle=True)
```

## 標準化
線形モデルでは標準化が必要
「モデルの学習と予測 - part1」では敢えて行わなかった

```python
from sklearn.preprocessing import StandardScaler

std_scl = StandardScaler()
x_train = std_scl.fit_transform(x_train)
x_valid = std_scl.transform(x_valid)
x_test = std_scl.transform(x_test)
```
StandardScalarメソッドの詳細は以下
> [Scikit-learnでデータのスケール変換（前処理）する - Hatena Blog](https://helve-python.hatenablog.jp/entry/scikitlearn-scale-conversion#StandardScaler%E3%81%AE%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89)

## 線形回帰の学習と予測精度の可視化（前処理あり）
part1の処理と同じ

```python
lr = LinearRegression()
lr.fit(x_train, y_train)
y_pred = lr.predict(x_valid)
y_pred_test = lr.predict(x_test)
print('='*20)
print('LinearRegression')
print(f'valid_RMSE: {np.sqrt(mean_squared_error(y_valid, y_pred))}')
print(f'test_RMSE: {np.sqrt(mean_squared_error(y_test, y_pred_test))}')
predict_visualizer(y_valid, y_pred, y_test, y_pred_test, 'lr')
```
![線形回帰02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/f6693bf9-9ae7-aee5-39d2-9d2ef075c05a.png)
結果から、RMSEは約6万となった
part1では約7万だったため、精度が良くなっている

## XGBoostの学習と予想精度の可視化（前処理あり）
part1の処理と同じ

```python
xgb = XGB.XGBRegressor(random_state=144)
xgb.fit(x_train, y_train)
y_pred = xgb.predict(x_valid)
y_pred_test = xgb.predict(x_test)
print('='*20)
print('XGBRegressor')
print(f'valid_RMSE: {np.sqrt(mean_squared_error(y_valid, y_pred))}')
print(f'test_RMSE: {np.sqrt(mean_squared_error(y_test, y_pred_test))}')
predict_visualizer(y_valid, y_pred, y_test, y_pred_test, 'xgbr')
```
![XGBoost02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/daa72f8c-3a95-dca0-17da-3c1eee9755e1.png)
結果から、RMSEは約5万となった
part1では約55000だったため、精度が良くなっている

## ランダムフォレストの学習と予測精度の可視化（前処理あり）
part1の処理と同じ

```python
rfr = RandomForestRegressor(random_state=144, n_estimators=100)
rfr.fit(x_train, y_train)
y_pred = rfr.predict(x_valid)
y_pred_test = rfr.predict(x_test)
print('='*20)
print('RandomForestClassifier')
print(f'valid_RMSE: {np.sqrt(mean_squared_error(y_valid, y_pred))}')
print(f'test_RMSE: {np.sqrt(mean_squared_error(y_test, y_pred_test))}')
predict_visualizer(y_valid, y_pred, y_test, y_pred_test, 'rfr')
```
![ランダムフォレスト02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792137/4b4aa6e8-73f2-eeb0-6695-670f9aefce98.png)
結果から、RMSEは約45000となった
part1では約49000だったため、精度が良くなっている

# まとめ
- Google Colaboratoryで機械学習をやってみた
- `california_housing`データを確認
- 前処理なしと前処理ありで予測精度の比較を行なった
- 前処理を行なって学習したモデルの予測精度が向上したことを確認した

**part1結果**

|モデル|検証用RMSE|テスト用RMSE|
|----|----:|----:|
|線形回帰|70139|69766|
|XGBoost|55100|55100|
|ランダムフォレスト|48458|49924|

**part2結果**

|モデル|検証用RMSE|テスト用RMSE|
|----|----:|----:|
|線形回帰|58568|60750|
|XGBoost|48254|51184|
|ランダムフォレスト|42473|45217|

今回行った前処理は外れ値の削除のみだった
しかし、前処理が全行程の8割を占めると言われるデータ分析ではまだまだ改善すべき問題が残っている

これを機に少しでもデータ分析に興味が湧いたなら、より良い予測精度を求めて他の前処理を試してみて欲しい

# その他参考文献
> - [【第１回カリフォルニア住宅価格の予測】前処理無しで精度を確認](https://zerofromlight.com/blogs/detail/65/)
- [【第２回カリフォルニア住宅価格の予測】特徴量エンジニアリング＆データクリーニング（データクレンジング）](https://zerofromlight.com/blogs/detail/66/#_3)
- [【第３回カリフォルニア住宅価格の予測】最良の機械学習モデルを選び評価を行う](https://zerofromlight.com/blogs/detail/67/)