学生による学生のためのデータサイエンス勉強会

【さきどりPython#9】kaggleのデータで線形回帰モデルをつくろう

historoid
historoid

こんにちは。清野(@historoid1)です。

早いもので、教科書も2周目に突入ですね!! 2周目もしっかり勉強していきましょう。

さきどりPythonでは『Python機械学習クックブック』を第13章の線形回帰から勉強してきました。

1周目の目標

一周目は「とりあえず動かせるようになる」ことと「アルゴリズムの概観を学ぶ」ことでした。

具体的に言うと、章の始めのレシピ2つか3つ目くらいまでを実装しつつ、解説してきました。

早いものでもう第20章のニューラルネットワークまで終了しました。そこで今週から線形回帰に戻って2周目を始めたいと思います。

2周目の目標

  1. kaggle等の外部データで機械学習モデルを動かす
  2. 外部データを扱うことでPandasの操作を学ぶ。
  3. Matplotlibによる可視化について学ぶ。
  4. (できれば)さらに先のレシピに触れて、より深くアルゴリズムを学ぶ。

2周目の目標は以上のようになります。

1周目では、scikit-learnの文法の一貫性のおかげで実装についてはほとんど問題ありませんでした。

きれいに整えられたデータセットを使って、同じ方法でモデルを作り、予測まで行ってきました。

2周目はより実践に近づけてもう一度アルゴリズムを学び直す予定です。

kaggleのデータで線形回帰モデルをつくろう

Google Colabのセットアップ

Google Colabのアカウント作成から、導入までは以下の記事にまとめてあります。まだGoogle Colabを使ったことがない方は参照してください。

【Google Colabolatory】プログラミング初心者が知るべきShellとGoogle Colaboratoryの話

kaggleデータのダウンロード

私たちの勉強会で使用するkaggleのデータ

今回使用するkaggleのデータセットは以下の3つです。

1. 生検データによる乳房腫瘍の診断

乳がんのデータセットです。

腫瘍には良性腫瘍と悪性腫瘍があり、乳がんの診断には腫瘍の穿刺吸引による生検を行います。

このデータセットでは、得られた細胞の特徴が説明変数として記録されています。

目的変数は、良性か悪性かのカテゴリ変数です。分類タスクの学習を勉強するときに使いましょう。

参考 乳がんデータセットkaggle
2. 国別幸福度の統計調査

国別の幸福度に関する調査をまとめたデータです。調査結果として、幸福度ランクという指標が出されています。これを目的変数としても良いでしょう。

幸福度ランクは最下位が158位です。これを回帰タスクとするか分類タスクとするかは人によります。約160個の分類問題とするか、0から160を出力する回帰とするかですね。

2012年、2013年、2015年の3年分のデータがあるので、時間経過を追っていく訓練にもなります。複数のファイルをどう扱うのか、データフレームのマージの勉強になるでしょう

参考 世界幸福度調査kaggle
3. アボカドの価格予測

アボカドの販売価格を予測するデータセットです。

説明変数が連続値のものが多いので、かなり取り組みやすいでしょう。データの前処理も考えずにモデルに入れるだけでも動作しそうです。

参考 アボカドの価格予測kaggle

2周目のさきどりPythonではこの3つを使用する予定です。

kaggleのウェブサイトでは、より精度を上げる方法が書かれていますが、はじめからそれを見るのではなく、まずは自分の知識を実装できるように努めましょう。

今回使うデータ

今回はアボカドの価格予測のデータを使います。

そのつもりで読んでいってくださいね。

kaggleのデータのダウンロードの方法

ダウンロードは簡単です。

タイトルの右下にあるDownloadを押せばOKです。

おそらくzip形式でダウンロードされ、その中身はcsvファイルでしょう。

そしてcsvファイルは、Google Driveに移動させてください。

Google ColabとGoogle Driveの連携

Google ColabとGoogle Driveの初期設定

すでに紹介しましたが、Google ColabとGoogle Driveの連携についてはまとめてあります。

この記事を読んで、Google Colabを使える状態にしておいてくださいね。

【Google Colabolatory】プログラミング初心者が知るべきShellとGoogle Colaboratoryの話

Google Drive上のファイルをGoogle Colabで読む

Google ColabもGoogle DriveもGoogleのサービスですが、動いているサーバーが違います

だからGoogle Driveにデータを入れたからといって、Google Colabですぐにそのデータを読み取れるわけではありません。

Google Driveのファイルの読み込み方は以下の記事でまとめてあります。

【Pythonによるデータ分析】Pandasの基本操作5選

ここまでのコードまとめ

この段階で、kaggleデータをGoogle Colabで読み込む段階まで終わりました。

参考記事を読み飛ばしたい人向けに重要な部分だけ書いておきます。

# Google DriveをGoogle Colabにマウントする
from google.colab import drive
drive.mount('/content/drive')

# csvファイルの読み込み
# データフレームの作成
import pandas as pd
df = pd.read_csv('/content/drive/My Drive/xxxx/xxxx.csv')

Pandasでデータを概観する

Pandasとは

Pandasとは

PandasはPythonの外部ライブラリで、データ解析には必須といえます。

参考 Pandas公式サイトpandas.pydata.org

Pandasで解析を始める

さっそくPandasを使って解析を始めましょう。

と言いたいところですが、以下の記事でも解析初期の手順を説明しています。参考にしてください。

今回はアボカドの価格予測のデータを使います。

特徴量(説明変数)の確認

ではデータを概観しましょう。

df.columns

これですべての列名が表示されます。

df.describe()

収まりきりませんが、こんなテーブルになっています。

df.describe()で表示されるのは計算可能な列のみです。注意してください。これはすべての列が表示されているわけではありません。

また、アボカドのデータはコンペデータではないので、全てのデータが揃っています。したがって、どれを目的変数・説明変数にするかは自分で決めてください。

今回の目的変数

今回はTotal Volumeを目的変数とします。

「価格じゃないんかーい」と思ったあなた。鋭いですね。

線形回帰をやりやすい変数を設定することにしました。

欠損値の確認

df.isna().any()

これからも言い続けていくと思いますが、欠損値の確認はまず先に行いましょう。エラーのもとです。

欠損値は先に確認せよ!!

エラーならまだいいんですけど、Pandasでの欠損値はnp.nanとして計算できてしまうところが問題なのです。

欠損値が出現するたびにエラーが起こると実務上はかなり面倒です。そう考えると欠損値があっても解析を進められる設計にすることは正しいのです。

しかし逆に、エラーが出ないから問題に気が付きにくいのです。何かしらの操作を行っても計算ができてしまうことに問題があります。

Pandasには、欠損値が混ざると計算結果がnp.nanになるものと、np.nanを飛ばして計算してくれる機能が混在しています。

解析が終わったあとで、「エクセルファイルを見直したら謎の改行があった」なんてことになれば、もう終わりです。

N数(サンプルサイズ)が正しいのかわからなくなるのです。

欠損値の確認はほんとに大事です。

ちなみにアボカドデータには欠損値はありません

Matplotlibでデータの可視化

2つのデータを選ぶ

これからMatplotlibで散布図を描くので、2つの変数を選びます。

1つはTotal Volumeです。アボカドの総販売数です。これを目的変数とします。実装ではyとおいています。

もう1つは説明変数です。これはTotal Bagsを選びました。

Matplotlibで散布図を描く

ではさっそく散布図を描いてみましょう。

Matplotlibの書き方はいろいろあるので、どれが正しいかはよくわかりません。

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('seaborn-whitegrid')

# グラフを描く場所を用意
fig = plt.figure(figsize=(10, 5))
# 空のグラフを用意
ax = plt.axes()

# データの用意
x = df['Total Bags']
y = df['Total Volume']

# 散布図をプロット
plt.plot(x, y, 'o', color='blue')

いい感じに相関してそうですね。正比例しすぎない感じがとても勉強向きです。

scikit-learnで線形回帰を行う

説明変数と目的変数を決定する

これは先ほどと同じですね。説明変数がTotal Bagsで、目的変数がTotal Volumeです。

線形回帰モデルをつくる

では教科書と同じように、モデルの作成から訓練まで進めます。

# ライブラリをロード
from sklearn.linear_model import LinearRegression

# 線形回帰器を作成
regression = LinearRegression()

# データ
feature = df[['Total Bags']].values  ##注意
target = df['Total Volume'].values

# 線形回帰器を訓練
model = regression.fit(feature, target)
注意

feature = df['Total Bags']ではエラーになります

ValueError: Expected 2D array, got 1D array instead:

「説明変数は2次元配列で渡せ」と言っています。

df['Total Bags']では、Seriesが返ってくるので1次元です。

これを回避するためにdf[['Total Bags']]にして、DataFrame(2次元)が返ってくるようにしています。

あるいは、df['Total Bags'].valuesで一旦NumPy配列にしてから、.reshape(-1, 1)で転置してもOKです。

学習結果を可視化する

学習した係数(傾き、重み)の確認

# 係数(傾き、重み)の確認
model.coef_
# array([3.37232184])

これだけ見てもなんともいえませんが、コードの確認として見てください。

学習した切片(バイアス)の確認

# 切片(バイアス)の確認
model.intercept_
# 42503.49912165059

ふむふむって感じですね。

学習した係数と切片で1次方程式を描いてみる

# 散布図を描く
fig = plt.figure(figsize=(10, 5))
ax = plt.axes()
x = df[['Total Bags']]
y = df['Total Volume']
plt.plot(x, y, 'o', color='blue')

# 回帰関数をプロット
plt.plot(x, model.predict(x), color='orange', linestyle='--')

いいですねー。ぴったり合致するところと、ちょっとズレているところがあって、今後の課題として良い分布です。

新しいデータを与えて推測する

これも確認を兼ねてコードにしてみます。

# 0行目のTotal Bagsで試す
# 次元を合わせるためreshap
tmp = np.array(8696.87).reshape(-1, 1)

# 予測する
model.predict(tmp)
array([71832.1437282])

実際の値は、\(64236.62\)です

残差は\(-7595.523728199994\)なので、10%くらいズレてる感じですね。

損失関数で評価する

残差平方和 RSS: residual sum of squares

損失関数にもいろいろな種類がありますが、まず残差平方和(residual sum of squares)を紹介します。線形回帰モデルの損失関数として一般的に使われています。

$$RSS = \sum_{i=1}^n (y_i – \hat{y_i})^2$$

\(y_i\)が実際の値(観測値)で、\(\hat{y_i}\)が予測値です。

では、さきほどの値でRSSを求めてみましょう(1つしか値がないので、総和という感じではありませんが……)。

$$RSS = (64236.62 – 71832.1437282)^2 = 57691980.705649145 $$

どうですか? 損失うんぬんの前に「値デカくね?」って感じませんか? 1つの推測値でこれですから、総和なんかとったら恐ろしいことになりそうです。

パソコン的にはあんまり大きな値は計算したくないので、RSSだけだとうーん……って感じですね。

標準化すると計算が楽になる

ここで勘の良い方は気付いたでしょう!!

値が大きくなりすぎるのを防ぐためにも標準化をするわけです。

標準化とは

まず分野によって意味が違います。それを忘れないでください。

scikit-learnでは、標準化 standardizationは平均を0、標準偏差を1にすることです。

平均二乗誤差 MSE:mean square error

RSSをデータの個数で割ったものが平均二乗誤差(MSE: mean square error)です。

さきほどは「値が大きくなりすぎる」ということで、\(n\)で割ってRSSの平均値を出してみます。

$$MSE = \frac{1}{n} \sum_{i=1}^n (y_i – \hat{y_i})^2$$

今は試しに1つしか値を求めてないので、\(n\)で割っても変わりません。ということは、平均値でもそこそこ大きな値になりそうですね。

分散とMSEは別物

一見すると\(MSE\)は分散と似ていませんか? でも違います。

分散は平均値と観測値のズレを2乗したものです。MSEは推測値と観測値のズレ(残差)を2乗したものです。

まあ、計算はほぼ同じですけど。

平均平方二乗誤差 RMSE: root MSE

ではもっと小さい値にするため、MSEの2乗をとっちゃいましょう!!

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

ちなみに先ほどの例で計算すると、$$57691980\fallingdotseq 7595$$です。

まあ、結果は小さくなっていますが、途中の計算で大きな値を扱うことは変わりませんよね? だから標準化は便利なんです。

平均絶対誤差 MAE: mean absolute error

MSEと似ていますが、こちらは絶対値の総和です。

$$MAE = \frac{1}{n} \sum_{i=1}^n \left|y_i – \hat{y_i}\right|$$

平均絶対誤差率 MAPE: mean absolute percentage error

MAEの割合バージョンです。観測値の大きさに対して、ズレの大きさを見ているわけです。相対誤差の1つです。

$$MAPE = \frac{100}{n} \sum_{i=1}^n \left| \frac{y_i – \hat{y_i}}{\hat{y_i}}\right|$$

割合なので、\(100\)はなくてもOKです。

平均平方二乗誤差率 RMSPE: root mean square percentage error

RMSEの相対誤差もあります。

$$RMSPE =\sqrt{\frac{100}{n} \sum_{i=1}^n (\frac{y_i – \hat{y_i}}{\hat{y_i}})^2}$$

これも\(100\)はなくても構いません。

https://bdarc.net/wp-content/uploads/2020/05/icon-1.pnghistoroid

誤差ってこんなに種類あったんですね。

損失関数で評価するにもデータが必要

scikit-learnにももちろん損失関数は備わっています。

mean_squared_error(a, b)

abをNumPy配列として渡してあげれば、損失が計算されます。

kaggleのデータを分割して検証する

kaggleのコンペであれば、訓練データだけが配布され、それから得られた予測値を提出することで損失が計算されます。そうやって成績を決めているわけです。

しかし今回のアボカドデータは、訓練データと検証データに分かれていません。

したがって、ちゃんと損失関数で計算したかったら、データを自分で分割する必要があります

そして実は、データを分割するメソッドも用意されています

from sklearn.model_selection import train_test_split

# 検証データを30%にする
ftr_train, ftr_test, tag_train, tag_test = train_test_split(features, target, test_size = 0.3)

こうやって分けた上で、ftr_traintag_trainでモデルを作ればOKです。


どうでしたか? kaggleで線形回帰モデルを訓練するイメージはできたでしょうか。

まずはこれをじっくり読んで、他の説明変数を使ってプログラムが動くかどうか試してみてください。

今後の課題(案)
  1. 他の説明変数で試してみる。
  2. 訓練データと検証データを分けて学習し、損失を計算する。
  3. 最も損失の少ない説明変数を探索する。

ただ「動きました」じゃ、あまり意味がありません。

動かせるようになることも重要ですが、それを使って何をすべきか考えてください。

与えられたデータではわからないかもしれませんが、実際には自分の研究や職務として解析をするわけです。

解析したことをどう活用できるのか、何を提案できるのかまで考えられればいいですね。

https://bdarc.net/wp-content/uploads/2020/05/icon-1.pnghistoroid

長くなりましたね。でも自分で動かすと楽しいですよ!!

自分でデータをいじるからこそアイデアも湧きますし、教科書の内容も身に沁みて理解できるようになります。

2周目も頑張りましょう。

https://bdarc.net/wp-content/uploads/2020/05/icon-1.pnghistoroid

私たちの勉強会の公式Twitterもはじめました。よかったらフォローしてください。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です