Pythonとsklearnで手軽に予測モデル作成の流れを感じよう

Pythonで機械学習がやってみたい
Scikit-learnを使って基本的な予測問題の流れをつかみたい

Pythonが流行っている昨今、Scikit-learnやDeepLearningライブラリを使ってみたいと思っている方、多いのではないでしょうか。

こんにちは、ライターのフクロウです。Pythonのインストラクターをしています。

この記事では、機械学習ライブラリ「Scikit-learn」(skleran)を使って、データの予測問題にチャレンジする流れを紹介します。解析に使うライブラリはsklearnだけなので(Deep Learningは触りません)、手軽に始められると思いますよ!

この記事はこんな人のために書きました。

  • Pythonで機械学習に挑戦したい
  • データを集めるところから最後までの流れが知りたい

なお、Pythonの記事については、こちらにまとめています。

目次

実験目的

Boston house-prices (ボストン市の住宅価格)データを使い、Scikit-learnのランダムフォレスト回帰で住宅価格を予測してみましょう。

 実験の前準備

ライブラリのimport

まずは必要なライブラリをインポートしましょう。

# 計算で使うかもしれないNumPy
import numpy as np
# データフレームを使うためにPandas
import pandas as pd

# 可視化ライブラリ
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
# もしもJupyter notebookで使う場合は、以下のコマンドが必要
%matplotlib inline

次にscikit-learn関係をインポートします。

# データセット
from sklearn import datasets
# ランダムフォレスト回帰のクラスをRFRというあだ名を付けてimport
from sklearn.ensemble import RandomForestRegressor  as RFR
 
# 教師データとテストデータに分割してくれる
from sklearn.model_selection import train_test_split

# 平均二乗誤差を計算する関数
from sklearn.metrics import mean_squared_error

# もしパラメータ探索がしたい場合は以下もimport
from sklearn.model_selection import GridSearchCV

# もしデータの標準化がしたい場合は以下もimport
from sklearn.preprocessing import StandardScaler

データの読み込み

回帰問題のベンチマークによく使われるボストンデータセットを読み込みます。ボストンデータの詳しい情報はscikit-learnに付属しているデータセットを読むのがおすすめです。

ここではデータを読み込んでから、train_test_split教師データとテストデータに分割してみます。

# ボストンデータの読み込み
boston = datasets.load_boston() 
 
# 教師データとテストデータに分割
train_data, test_data, train_target, test_target \
= train_test_split(boston.data, boston.target, test_size=0.2)

読み込んだデータセットをデータフレームにして表示してみましょう。すべてを表示すると膨大です。ここでは先頭の10行だけ表示します。

# データフレーム化 
train_df = pd.DataFrame(train_data, columns=boston.feature_names)

# 上から10行を表示
train_df.head(10)

読み込んだデータフレーム

# 予測したい値
train_df["MEDV"] = train_target

train_df.head()

予測したい値を追加したデータフレーム

データのチェック

まずはデータの個数と、どんなデータ型をもっているのかを確認しましょう。

train_df.info()

[出力結果]

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 404 entries, 0 to 403
Data columns (total 14 columns):
CRIM       404 non-null float64
ZN         404 non-null float64
INDUS      404 non-null float64
CHAS       404 non-null float64
NOX        404 non-null float64
RM         404 non-null float64
AGE        404 non-null float64
DIS        404 non-null float64
RAD        404 non-null float64
TAX        404 non-null float64
PTRATIO    404 non-null float64
B          404 non-null float64
LSTAT      404 non-null float64
MEDV       404 non-null float64
dtypes: float64(14)
memory usage: 44.3 KB

さて、読み込んだデータに欠損値があったら計算がおかしくなります。なのでisnullメソッドで欠損値の数を数えてみましょう

もしも欠損値があったら、これを別の数字で置換する必要があります。

# null(None)があれば1以上の値になります。
train_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
MEDV       0
dtype: int64

ここでは欠損は無いことがわかったので、次に進みます。

統計量を表示してみましょう。実はDataFrameにはdescribeという便利なメソッドがあるので、コレを使うことでDataFrameの統計量を一気に表示できます。

# 統計量の表示
train_df.describe()

代表値の表1

代表値の表2

特徴同士の関係を確認してみましょう。ここではseabornのpariplot関数で一気にやってしまいます。

このグラフを見ることで、どの特徴がどの特徴に似ているのかがわかります。非常に似ている特徴があるならば、それを参考に特徴を省くことも出来ます。

pairplot

ここではデータの特性についての考察は行っていません。本来であれば特徴エンジニアリングを行います。

予測精度が高くなるような特徴を作ったり、不要な特徴を削除したりと言った作業がこれに該当します。

回帰分析

ランダムフォレストの学習

今回は住宅価格をそれ以外の情報から予測するのが目的です。ランダムフォレスト回帰を使ってやってみましょう。

sklearnには様々な機械学習モデルが実装されていますが、データと目的にあったものを選ぶ必要があります。これについては勉強する以外にありませんが、一つの指針としてsklearnのチートシートを見てみるのも手です。

Choosing the right estimator

RFRクラスは並列処理で訓練時間を短縮できるので、n_jobsに使えるコア数を指定しておきましょう。

rg = RFR(n_jobs=-1, random_state=2525) # n_jobs=-1でコアすべてを使って並列に学習できる
 
rg.fit(train_data, train_target) # 訓練

[出力結果]

RandomForestRegressor(bootstrap=True, criterion='mse', max_depth=None,
           max_features='auto', max_leaf_nodes=None,
           min_impurity_decrease=0.0, min_impurity_split=None,
           min_samples_leaf=1, min_samples_split=2,
           min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=-1,
           oob_score=False, random_state=2525, verbose=0, warm_start=False)

このような問題では、このようにデフォルトの引数をそのまま使うのは賢いやり方ではありません。

ちゃんとやる場合はグリッドサーチやランダムサーチなどのパラメータサーチを行って、もっともらしい値を探す必要があります。また、クロスバリデーションによってモデルの評価を行う必要もあります。

学習結果の確認

まずは訓練データにどのくらいfitできたか確認してみましょう。

ここでは訓練データの住宅価格(target)と、モデルの予測した住宅価格の平均二乗誤差を出してみましょう。(この値は小さいほど嬉しいものです。)

predicted_train_target = rg.predict(train_data)
mean_squared_error(train_target, predicted_train_target)

[出力結果]

0.9729691006642613

それなりによく出来ていることがわかります。ですがこれで安心してはいけません。訓練データに対してfit出来ていても、テストデータに対してどうなのかはまだわかりませんからね。

ではテストデータの方も表示してみましょうね。

predicted_test_target = rg.predict(test_data)
mean_squared_error(test_target, predicted_test_target)

[出力結果]

10.828846078431374

R^2のスコアも見てみます。

rg.score(test_data, test_target)

[出力結果]

0.8540704890041346

この値はそこまで良いものではありませんね。また、これを更に良くするには、先程紹介したパラメータサーチやクロスバリデーションを使ってチューニングを行ったり、データの前処理をよりしっかり行う必要があります。

また、ここではランダムフォレストだけを使いましたが、SVMなどの別の機械学習モデルを複数使い、それらをアンサンブルすることでも、さらなる性能向上が期待できます。

まとめ

この記事では、Pythonを使ってシンプルなデータの予測を行いました。

scikit-learnは非常に便利で使いやすいライブラリです。例えば、今回使ったランダムフォレストについても、どういう手法なのか分からなくてもある程度動かすことが出来ました。ただし、しっかりと使いこなすには勉強が必要です。自分で実装できるようにとまでは行かないでも、どういう手法なのかイメージが湧く程度までは最低限覚えておきたいですね。

最後に、ここで紹介した処理の一覧はあくまでも流れを把握するのが目的だと思ってください。記事中に散りばめた「これをしたほうがいい」という前置きのあるキーワードを自分で調べて試してみるのが重要ですよ。

この記事を書いた人

第一言語はPythonです。
皆さんRustやりましょう。

目次