【scikit-learn基礎】実際に線形回帰モデルを構築する

# はじめに
機械学習初心者がscikit-learnの学習をアウトプットするために実際のデータを使って予測モデルを構築します。

今回は一番シンプルな線形回帰モデルについて取り組んでいこうと思います。

# 実行環境
Python3
MacBook Air（端末）
Jupyter Lab（Chrome）

# 本記事の概要
**1.背景、目的**
**2.データの取得、前処理**
**3.モデル構築**
**4.モデル評価**
**5.結論**

# 本編
## 1.背景、目的
前回の記事でSQLの実践を兼ねて[bigqueryの一般公開データセット](https://console.cloud.google.com/marketplace/browse?filter=solution-type:dataset&hl=ja&_ga=2.3576376.901277918.1691022509-770150938.1686033464)にある[Chicago Taxi Trips](https://console.cloud.google.com/marketplace/product/city-of-chicago-public-data/chicago-taxi-trips?hl=ja&project=sql-task-394800)というデータから、SQLを記述してデータを取得してみるということを行いました。

アメリカ・シカゴ市のタクシー利用に関するデータがまとめられています。

前回ではデータからアメリカのチップ文化を知るというのが大きな目的でした。

前回の記事

https://qiita.com/kizakiza/items/3c504273c8ecee0146b7

最後の分析のところで、乗車距離が長いほど支払うチップの金額が大きくなっていることがわかりました。

そこで、今度は最近勉強したscikit-learnの実践も兼ねて乗車距離に対するチップの支払い金額を予測するモデルを構築してみようと思います。

## 2.データの取得、前処理
### データの取得
Jupyter Lab上でbigqueryにアクセスし、Chicago Taxi Tripsにある乗車距離とチップの金額のデータを取り出します。
取り出したデータをデータフレームに格納します。

bigqueryでデータを取り出す段階で欠損値を避けています。

```python
from google.cloud import bigquery
import pandas as pd

client = bigquery.Client()

query = """
    SELECT 
        trip_miles, tips
    FROM
        bigquery-public-data.chicago_taxi_trips.taxi_trips
    WHERE
        trip_miles IS NOT NULL AND tips IS NOT NULL
"""

query_job = client.query(query)

df = query_job.to_dataframe()
```

どのようなデータが入っているか確認してみます。
```python
df.head()
```

[出力結果]
|  | trip_miles | tips |
|:-:|:-:|:-:|
| 0  | 4.70  | 2.0  |
| 1  | 22.50  | 0.0  |
| 2  | 9.90  | 0.0  |
| 3  | 3.51  | 0.0  |
| 4  | 0.33  | 0.0  |

### データの前処理
外れ値がないかを確認します。箱ひげ図を用いてみます。
```python
import matplotlib.pyplot as plt
%matplotlib inline

# trip_milesの箱ひげ図を描画
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.boxplot(df['trip_miles'])
plt.title('Boxplot of trip_miles')

# tipsの箱ひげ図を描画
plt.subplot(1, 2, 2) 
plt.boxplot(df['tips'])
plt.title('Boxplot of tips')
```
[出力結果]
![スクリーンショット 2023-08-10 15.02.18（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2741553/1bb92119-2c61-3d00-5362-8332ff6fc900.png)

大きく飛び出ているデータは見当たらないため、外れ値の除外は行わずに行きたいと思います。

## 3.モデル構築
ここでは線形回帰モデルを使用します。特徴量は乗車距離のみで、乗車距離とチップの金額は比例関係にあるかもしれないと前回の記事で判断したため線形回帰モデルを選択しました。

![スクリーンショット 2023-08-04 11.16.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2741553/231cddb8-097f-1e76-ad6d-97a6774ce622.png)
乗車距離が長いほど、チップの支払い金額の平均が大きくなっていることがわかります。

```python
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression

# データの分割
X = df[['trip_miles']]  # 2次元のデータフレームとして抽出
y = df['tips']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# モデルの学習
model = LinearRegression()  #線形回帰モデル
model.fit(X_train, y_train)
```

これでモデルの学習が完了しました。

## 4.モデル評価
### 予測
モデルを構築したことで、乗車距離がわかれば大体のチップの金額を予測することができるようになります。
試しにテストデータに対する予測を行ってみます。
```python
# 予測
import numpy as np
X_new = np.array(100).reshape(-1, 1)
model.predict(X_new)
```
[出力結果]
array([6.53816979])

乗車距離が100マイルの時のチップの支払い金額はおよそ6.5ドルだと予測してくれました。

### 評価
回帰モデルで使われる評価指標は`MSE`、`RMSE`、`MAE`、`R-Squared`などいくつかあります。今回は`RMSE`を用います。

`RMSE`は`MSE`に平方根をつけたものです。

```math
RMSE = \sqrt{\frac{1}{n}\sum_{i=1}^{n}(y_i - \hat{y}i)^2}
```
`MSE`は残差の二乗の平均を表します。`MSE`のままだと単位が二乗になるので指標の解釈がしづらいという問題点があります。

`RMSE`は指標の単位が目的変数の単位と一致するので解釈しやすくなります。

```python
from sklearn.metrics import mean_squared_error

# 学習データでの予測と評価
train_preds = model.predict(X_train)
train_rmse = mean_squared_error(y_train, train_preds, squared=False)

# テストデータでの評価と予測
test_preds = model.predict(X_test)
test_rmse = mean_squared_error(y_test, test_preds, squared=False)

print(f'Training RMSE: {train_rmse}')
print(f'Test RMSE: {test_rmse}')
```
[出力結果]
Training RMSE: 2.7169623466582067
Test RMSE: 2.7211446819405705

学習データでのRMSEとテストデータでのRMSEの値が近いことからモデルは過学習していないことがわかります。また、このモデルは新しいデータに対しても十分な予測を行う性能を持っていることがわかります。

`RMSE`がおよそ2.7ということは、チップの支払い金額の平均的な誤差が2.7ドルであると言えます。
**3.モデル構築**の乗車距離と乗車距離に対するチップの支払い金額の平均の表を確認すると、およそ1.3ドルから8.43ドルの間で推移していることから、誤差が2.7というのはかなり大きいということがわかります。

## 5.結論
タクシーの乗車距離からチップの支払い金額を予測するモデルを線形回帰モデルを使って構築しました。

乗車距離からチップの支払い金額を予測するモデルを完成させることはできましたが、残念ながら`RMSE`の結果からモデルの精度は高いとは言えない結果になりました。

乗車距離だけでなく、乗車時間や乗車日など他の特徴量を考慮したり不均衡データになっていないかの確認など特徴量エンジニアリングに関しても積極的に取り組んでいく必要があることがわかりました。

# まとめ
scikit-learnの実践ということで、シンプルな線形回帰モデルの構築に取り組みました。

機械学習の手法をインプットしているときはなかなか内容を理解することが難しかったですが、実際にモデルを作ってみることで特徴量エンジニアリングの必要性や評価指標の数字感覚を実感することができました。

今度は特徴量を増やすなどして精度の高いモデルを作れるように頑張ります。