ロゴ ロゴ

scikit-learnで機械学習 ~回帰編~

はじめに

こんにちは。とうとう春休みですね。
私は半月ほど前から、暇を極めすぎて機械学習の勉強を始めました。
そのため、今回は機械学習(回帰)についてブログを書いていこうと思います!
(また、機械学習を勉強していて疑問に思った内容をまとめたブログを近いうちに書くつもりです。ぜひご覧ください。)

今回の内容

scikit-learnを利用して機械学習(回帰)をしていきます。
「scikit-learn」とは、Pythonの機械学習で用いられるオープンソースライブラリです。
今回は、「ボストンの住宅価格データ」を使用しました。

<目次>
1.データを取り込む
2.線形回帰を用いる
3.リッジ回帰を用いる
4.ラッソ回帰を用いる
5.Elastic Netを用いる
6.考察
7.おまけ

1.データを取り込む

 まずは、データを取り込んで行きましょう。

import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt

#ボストンの住宅価格データを読み込む
from sklearn.datasets import load_boston
boston = load_boston()

#説明変数
boston_df = pd.DataFrame(boston.data,columns=boston.feature_names)
#目的変数
target_df = pd.DataFrame(boston.target,columns=['target'])

以上で読み込みは完了しました。
データ数や、欠損値などについては【7.おまけ】に少し書きました。気になる方はそちらも読んでみてください。
今からいくつかのアルゴリズムを実装していこうと思います。

2.線形回帰を用いる

まずは、線形回帰を使います。

from sklearn.linear_model import LinearRegression

#説明変数
X = boston_df
#目的変数
y = target_df

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

model = LinearRegression()
model.fit(X_train,y_train)

#決定係数(R^2)について
print('決定係数_train:',model.score(X_train,y_train))
print('決定係数_test:',model.score(X_test,y_test))

<出力結果>

決定係数_train: 0.7645451026942549
決定係数_test: 0.6733825506400194

出力結果から、そこまで悪くない結果になっていることがわかります。また、訓練データとテストデータの決定係数の値が少し離れてしまっていました。他のデータだと決定係数が大きく違うことがあり、その場合は「過学習」を起こしていることになります。
次は、他のアルゴリズムを利用して精度が上がるか確かめてみましょう。

3.リッジ回帰を用いる

線形回帰は、特徴量が多い場合に過学習を起こしやすいです。
リッジ回帰では、L2正則化を行うことで制約をを強くし、過学習の危険性を減らしています。

from sklearn.linear_model import Ridge

ridge_model = Ridge()
ridge_model.fit(X_train,y_train)

print('決定係数_train:',ridge_model.score(X_train, y_train))
print('決定係数_test',ridge_model.score(X_test, y_test))

<出力結果>

決定係数_train: 0.7623440182689594
決定係数_test: 0.6665819091486688

結果は線形回帰とほとんど変わりませんでした。
今よりも精度を上げるためには、学習率αを変更していくことが必要です。

4.ラッソ回帰を用いる

最後に、ラッソ回帰を用いてみます。
ラッソ回帰では、L1正則化を行います。自動的に重要な特徴量を判別してくれるため、リッジ回帰に比べると理解しやすいと思います。

import numpy as np
from sklearn.linear_model import Lasso

lasso_model = Lasso()
lasso_model.fit(X_train,y_train)

print('決定係数_train:',lasso_model.score(X_train, y_train))
print('決定係数_test:',lasso_model.score(X_test, y_test))
print('使用した特徴量の数',np.sum(lasso_model.coef_ != 0))

<出力結果>

決定係数_train: 0.7084095500978869
決定係数_test 0.6115433359595555
使用した特徴量の数: 10

結果は、線形回帰やリッジ回帰よりも精度が下がりました。
出力結果から、14個の特徴量うち10個が使われたそうです。
今よりも精度を上げるためには、(リッジ回帰と同様)学習率αを変更する必要があります。

5.Elastic Netを用いる

Elastic Netは、リッジ回帰とラッソ回帰を組み合わせたものです。

from sklearn.linear_model import ElasticNet

elanet_model = ElasticNet()
elanet_model.fit(X_train,y_train)

print('決定係数_train:',elanet_model.score(X_train, y_train))
print('決定係数_test:',elanet_model.score(X_test, y_test))

<出力結果>

決定係数_train: 0.7123645785314915
決定係数_test: 0.6172050826795714

線形回帰やリッジ回帰よりも精度が下がりました。
ラッソ回帰と結果がかなり近いですね。実際、学習率α=1に近いほどラッソ回帰に近づくため、理論上は間違っていないはずです。

6.考察

最後に、リッジ回帰とラッソ回帰、Elastic Netで学習率αを何回か変更してみました。すると、あまり変化がなかったため考察では学習率α=0.0001として実行してみました。
結果は以下の通りです。

from sklearn.linear_model import Ridge

ridge00001_model = Ridge()
ridge00001_model = Ridge(alpha=0.0001).fit(X_train, y_train)
print('<リッジ回帰>')
print('決定係数_train:',ridge00001_model.score(X_train, y_train))
print('決定係数_test:',ridge00001_model.score(X_test, y_test))

import numpy as np
from sklearn.linear_model import Lasso

lasso00001_model = Lasso()
lasso00001_model = Lasso(alpha=0.0001,max_iter=100000).fit(X_train, y_train)
print('<ラッソ回帰>')
print('決定係数_train:',lasso00001_model.score(X_train, y_train))
print('決定係数_test:',lasso00001_model.score(X_test, y_test))
print('使用した特徴量の数:',np.sum(lasso00001_model.coef_ != 0))

from sklearn.linear_model import ElasticNet

elanet00001_model = ElasticNet(alpha=0.0001)
elanet00001_model.fit(X_train,y_train)

print('<Elastic Net>')
print('決定係数_train:',elanet00001_model.score(X_train, y_train))
print('決定係数_test:',elanet00001_model.score(X_test, y_test))

<出力結果>

<リッジ回帰>
決定係数_train: 0.7645451026093618
決定係数_test: 0.6733817267353814
<ラッソ回帰>
決定係数_train: 0.7645450589499895
決定係数_test: 0.6733642044843211
<Elastic Net>
決定係数_train: 0.764542197028621
決定係数_test: 0.6732266936025846

今回はアルゴリズムによって大きく精度が変化しませんでしたが、はじめに行った線形回帰とほぼ同じ出力結果を得ることができました。
また、Elastic Netについては学習率α=0に近いほどリッジ回帰に近づくため、【3.リッジ回帰を用いる】の出力結果と似たような値になっています。
次は、実データや他のデータセットを用いて結果が変わるかどうか確かめたいと思います。

7.おまけ

データの中身を少し確認してみましょう。

①データの数を確認する

all_df = pd.concat([boston_df,target_df],axis=1)
all_df.shape

<出力結果>

(506, 14)

all_dfとは、boston_dfとtarget_dfを組み合わせたものです。
axis=1は、boston_dfの隣にtarget_dfのデータをおいたことを表しています。(データ数が同じだから)
また、出力結果よりこのデータは506行、14列のデータであることがわかりました。

②欠損値を確認する

次に、欠損値を確認します。欠損値とは、名前の通り「欠けている値」のことを表しています。

all_df.isnull().sum()

<出力結果>

CRIM       0
ZN         0
INDUS      0
CHAS       0
NOX        0
RM         0
AGE        0
DIS        0
RAD        0
TAX        0
PTRATIO    0
B          0
LSTAT      0
target     0
dtype: int64

ここでは、データ全体に欠損値があるかを確認しました。
出力結果の通り、このデータに欠損値はありません。

③データの型を確認する

最後に、データが数値(intやfloat)か、文字列か(object)かを確認します。

all_df.dtypes

<出力結果>

CRIM       float64
ZN         float64
INDUS      float64
CHAS       float64
NOX        float64
RM         float64
AGE        float64
DIS        float64
RAD        float64
TAX        float64
PTRATIO    float64
B          float64
LSTAT      float64
target     float64
dtype: object

結果の通り、all_dfは全て数値であることがわかりました。非常にありがたいです。

おわりに

最後まで読んでいただきありがとうございます。
まだまだ勉強中なので、もっと勉強して良いブログを書くことが出来るように頑張ります。
今回は線形モデルを扱いましたが、他のアルゴリズム(SVRなど)で行うことも可能です。機会があったらブログに書くかも…
次からのブログも、機械学習の内容を書いていこうと思っています。お楽しみに!

コメント入力

関連サイト