scikit-learnとTensorflowで単回帰を実装する

去年AIに関心を持ち、何故か深層学習の勉強から始めてしまっていましたが、ちょっと深層学習以外の機械学習も知っておこうと思ったので、
今回はその基礎の基礎である単回帰の仕組みを知るとともに、実装力を付けていくことを目標にします。
今回用いたコードはGithub上にもあげています。

 

目標

 

単回帰の理解を深め、それをPythonのライブラリやフレームワークを使って実装できるようになる。

 

回帰とは

 

変数間の関係を関数で表すことです。
中でも線形(直線のやつ)の関数で表現するもののことを線形回帰と言います。

 

いつ使うのか

 

・他の変数を知っている時にある変数を予測したい
・2つ、またはそれ以上の変数間の関係を説明もしくは理解したい

【引用元】データサイエンス講義

 

何が嬉しいのか

 

「原因と結果の関係」がありそうなデータの関係を数式で表現することで、データの予測をすることができます。

順序的には、
1. 目的変数を決める
2. 目的変数のヒストグラムや折れ線グラフを見てみる
3. 何らかの説明変数との散布図などを可視化し、相関関係や外れ値などを確認する

というような感じになるかと思います。

 

この「目的変数」と「説明変数」を決める時に、
「結果」と「原因」の関係性であることにも注意しましょう。

 

例えば、「売上数」と「気温」を選んだとすると、
「N度だった」→「売り上げがM個になった」という時間的変化があるようなイメージです。

 

 

例えばあるコンビニのバイトさんが、
日替わり弁当を今日はいくつ発注するか悩んでいるとします。

彼女が感覚でなんとなく「100個売れる」と予想したとき
・実際に売れたのが60個だった→40個廃棄しないといけない
・実際には200個売れるはずだった→100個分の売り上げを得る機会損失をしてしまう

 

だから、理想を言えば、
「今日はN個売れる!だからN個注文しよう!!」→N個ぴったり売れきれる
としたいのです。
しかし、そう簡単に未来予想なんてできません。

 

ここで、回帰を使えます。
過去の日別の購買データに以下のような項目があったとします。

  • 売上数
  • 時間
  • 気温
  • 降水量
  • 日替わりメニュー
  • カロリー

ここで、知りたい数値はなんでしょうか。
そう、売上数ですね。
なのでこれを「目的変数」とします。

 

また、この「売上数」と深い相関関係がありそうなパラメータを他から選びます。
例えばここでは、「気温」を選択してみます。これが「説明変数」になります。

 

この「売上数」を縦軸、「気温」を横軸にして散布図にプロットしてみます。

さらに、そこに「イイカンジ」の直線を1本引いてみると以下のようになります。

すると、あら不思議。
今日の気温さえわかれば売り上げが予想できるようになるわけですね。

 

すると、例えば今日の気温が35度の時、グラフの横軸が35度のところを見ると、縦軸は約60くらいを指しているので、
60個の日替わり弁当を発注すれば(このグラフが正しければ)まぁ、ええかんじだろうってことになりますね。

 

実装時には、このように売上数を求めたい気温のリスト例えば、20度、30度、34度のときの売上数が知りたい
とすると(20度、30度、34度)をtestXとし、そのy座標が求めたい数値であるtestYになります。

 

単回帰を実装する

 

前置きが長くなりましたが、ここから実装していきます。
ちなみに単回帰というのは 1つの目的変数を1つの説明変数で表現することです。
対概念として重回帰というものもあります。

 

機械学習のライブラリはいくつかありますが、単回帰に関しては大体のライブラリで実装できます。
まぁ、シンプルな数学なので、やろうと思えばスクラッチでも楽々実装できちゃいます。意味があるのかどうかはわかりませんが。

 

要は、

という数式をイイカンジに満たす「a」と「b」を探します。

 

scikit-learnで実装する

 

scikit-learnではLinearRegression()を使います。

 

流れ的には
1. 訓練データのXとYから良い感じの傾きと切片を求める
2. テストデータのXから知りたかったtestYを出力させます。

超シンプルです。

 

いろいろオプションを取れるので以下のサイトを参考にしてみてください。

【参考】
sklearn.linear_model.LinearRegression — scikit-learn 0.19.1 documentation
scikit-learn で線形回帰 (単回帰分析・重回帰分析) – Python でデータサイエンス

 

コード全体は以下のような感じです。
ここから少々かいつまんで解説を加えます。

 

まず、重要なのは、この2行ですね。
解析自体はこの2行だけで完結しています。

model1.fit()で、引数には、
fit(説明変数、目的変数)
の順番に代入します。

 

これだけで解析が終わり、model1.coef_とmodel1.intercept_で求めたかった係数と切片が得られます。
後はこれをプロットするだけです。

今回は
coef = -2.5023821
intercept = 134.79948383749922
という値が得られました。

 

また、テストデータがある場合(例えば今日の気温とか)は、
以下のコードを実行することで、この解析結果とテストデータから算出される解が得られます。

 

このプログラムによって可視化された図が上に貼った、散布図と直線の図になります。

 

TensorFlowで実装する

 

TensorFlowで線形回帰を実装するときはscikit-learnのときほど簡単にはいきません。
計算グラフを考える必要があるので、今回は逆行列法を用いて実装します。

 

逆行列法とは

 

この図のn個あるプロットの1プロット1プロットの座標を(x1,y1),(x2,y2)..(xn,yn)のように見ていきます。

 

また、先ほど見たように係数と切片をそれぞれw1,w0と見てみて、行列同士の掛け算のように考えます。
\mathbf{y} = \mathbf{X}\mathbf{w}

 

y,wは以下のようになります。
 \mathbf{y}=\begin{pmatrix}  y_{1} \\  y_{2} \\  \vdots \\  y_{n}  \end{pmatrix}

\mathbf{w}=\begin{pmatrix}  w_{0} \\  w_{1}  \end{pmatrix}

 

ここで、行列計算した時に良い感じにy_{1} = w_{0} + w_{1}x_{1}になるように、
Xを以下のような行列で表現します。
この行列のことを「計画行列」と呼びます。
\mathbf{X}=\begin{pmatrix}  1 & x_{1} \\  1 & x_{2} \\  \vdots & \vdots \\  1 & x_{n}  \end{pmatrix}

 

先ほど散布図「イイカンジ」に線を引く。
と書きましたが「イイカンジ」ってどういう意味でしょうか。

要するに、全プロットに対し、最も誤差が少なくなるような線のことです。
詳しくは「最小二乗法」などで検索してみてください。

 

他にも色々方法はあるのですが、今回は誤差関数に最小二乗法を用います。
数式的には以下のようになります。

ちょっとややしこしくなってしまい恐縮ですが、ハットがついている方のyが上のn \times 1ベクトルです。

 

この誤差関数が最小値を取る時のwが求めたい解になります。

 

どのようにして求めるかというと、この誤差関数をwで偏微分し、その値が0になる時のwを見ます。
\frac{\partial R(\mathbf{w})}{\partial\mathbf{w}} = -2\mathbf{X}^\mathrm{T}(\mathbf{\hat{y}}-\mathbf{Xw}) = 0

 

これを式変形して、

 

以上より、
\mathbf{w}=(\mathbf{X}^\mathrm{T}\mathbf{X})^{-1}\mathbf{X}^\mathrm{T}\mathbf{\hat{y}}
を求めれば良いと言うことになります。

 

これを参考にしてコードに落とし込みます。

 

実装

 

Tensorflowで逆行列法を用いた単回帰のコード全体は以下のようになります。

 

少し解説を加えます。
以下の部分で計画行列Xを作成しています。

 

また、TensorFlow独特の実装法なのですが、
この部分では値を代入せず、式だけで作成し、計算もnumpyを使わずにTensorFlowのみで実装します。

 

TnesorFlowで実装する時に注意することに行列やベクトルのサイズや型があります。
計算するもの同士の型が異なっていたり、サイズが適切でないとエラーが返されます。

 

例えば、行列同士の積を計算するtf.matmul()は型変換を行わないので、同じ型のものを代入する必要があります。
そうしなければTypeError: Input 'b' of 'MatMul' Op has type int64 that does not match type float64 of argument 'a'.のようなエラーが返されます。

 

これを回避するためにはtf.cast()を使ってキャストするか、そもそも計算グラフの実装の仕方を工夫する必要があります。

 

変数xのデータ型を確認するにはtf.shape(x)を使います。

 

以上のプログラムによって得られた結果が以下です。
scikit-learnを用いたときとほとんど同じ値が得られています。
coef: -2.5023821023693498
intercept: 134.79948383749905

 

可視化した結果です。
見てわからないくらいわずかにさっきのと違います。

 

Kerasで実装する

 

わざわざやるほどでもないなと思ったので以下を参考にしてみて下さい。

【参考】
Regression Tutorial with the Keras Deep Learning Library in Python – Machine Learning Mastery

 

Seabornで実装する

 

複雑なことをしないで描画のみしたい場合はseabornを使うのが最も楽です。
たった1行のコードで描画まで行えます。

 

 

 

薄い青色の部分は98%の信頼区間です。
以下の記事が詳しいので参考にしてみてください

 

【参考】
Regression Tutorial with the Keras Deep Learning Library in Python – Machine Learning Mastery – Google 検索

コメントを残す