Deep Karmaning

技術系の話から日常のことまで色々と書きます

tensorflowで重回帰分析

概要

tensorflowで重回帰分析をやってみました。

わざわざtensorflowで重回帰分析を行うことは実務上中々ないと思うのですが、tensorflowの理解を深めるためのメモです。

今回使ったコードは以下です。

linear regression.ipynb · GitHub

参考したのは以下の記事。

aqibsaeed.github.io

環境

環境は以下の通り。

  • Mac 10.10.5
  • Jupyter 4.3.0
  • tensorflow 1.1.0
  • pandas 0.20.3
  • numpy 1.12.1
  • scikit-learn 0.19.0

手順

ライブラリ読み込み

ライブラリはnumpypandastensorflowscikit-learnを使います。

scikit-learnはBostonデータの読み込みと、標準化のために使います。

import tensorflow as tf
import numpy as np
import pandas as pd
from sklearn.datasets import load_boston
from sklearn.preprocessing import StandardScaler

データ準備

Bostonデータセットを読み込み標準化を行います。

最急降下法機械学習の際は特徴量を標準化する必要あり)を用いるので、標準化を行う必要があります。時々忘れるので注意です。

#ボストンデータ読み込み
boston = load_boston()
df = pd.DataFrame(boston.data, columns = boston.feature_names)
df['target'] = boston.target

#学習データ準備
f_num = df.shape[1] - 1
train_X = np.array(df.iloc[:, :f_num])
train_Y = np.array(df.iloc[:, f_num: f_num + 1])
n_samples = train_X.shape[0]

#正規化
ss = StandardScaler()
ss.fit(train_X)
train_X = ss.transform(train_X)

変数とプレースホルダー設定

変数とプレースホルダーの設定です。

#プレースホルダー
with tf.name_scope('data'):
    X = tf.placeholder(tf.float32, shape = [None, f_num ], name = "X")
    Y = tf.placeholder(tf.float32, name = "Y")

#変数(パラメータ)
with tf.name_scope('parameter'):
    W = tf.Variable(tf.zeros([f_num, 1]), name = "weight")
    b = tf.Variable(tf.zeros([1]), name = "bias")

モデル定義

次ににモデルの定義です。

参考記事では、ベクトル化した書き方ではないため、プレースホルダーのXを複数定義しています。

しかしそれではスケールしないので今回はベクトル化した書き方をしています。

#モデル
with tf.name_scope('model'):
    pred = tf.add(tf.matmul(X, W), b) #matmulは行列の積

損失関数、決定係数の定義

パラメータの学習のために、損失関数をMSE(mean square error)を使います。

MSE = \frac{1}{N} \sum (f_i -y_i)^{2}

この損失を最小にするようにパラメータを求めます。

#損失関数
with tf.name_scope('loss'):
    # Mean squared error
    loss = tf.reduce_mean(tf.square(pred - Y))
    tf.summary.scalar('loss', loss)

optimizer = tf.train.GradientDescentOptimizer(learning_rate = 0.01)
train_step = optimizer.minimize(loss)

#決定係数(R2)
with tf.name_scope('r2'):
    r2 = 1 - (tf.reduce_sum(tf.square(Y - pred)) / tf.reduce_sum(tf.square(Y - tf.reduce_mean(Y))))
    tf.summary.scalar('r2', r2)

学習

最後に学習です。1000ステップ学習を行い、学習過程のパラメータと最後のパラメータを出力します。

with tf.Session() as sess:
    # ログの設定
    summary = tf.summary.merge_all()
    writer = tf.summary.FileWriter("boston_log", sess.graph)
    
    sess.run(tf.global_variables_initializer())#変数初期化
    
    for i in range(1000):
        sess.run(train_step, feed_dict={X: train_X, Y: train_Y})
        if i != 0 and i % 200 == 0: # 200ステップごとに精度を出力
            train_summary, train_loss, train_r2 = sess.run([summary, loss, r2], feed_dict={X: train_X, Y:train_Y})# コストと精度を出力
            writer.add_summary(train_summary, i) #summaryの更新
            
            print("Step:", '%04d' % (i), "loss=", "{:.9f}".format(train_loss), "r2=", "{:.9f}".format(train_r2), "W=", sess.run(W), "b=", sess.run(b))            
            
    training_cost, training_r2 = sess.run([loss,r2], feed_dict={X: train_X, Y: train_Y})
    print("Training cost=", training_cost, "Training r2=", training_r2, "W=", sess.run(W), "b=", sess.run(b), '\n')

まとめ

まだまだtensorflowは慣れておらず、関数の意味が分かっていないところもあり、またtensorflowで重回帰分析を行っている事例が少なくて、苦労しました。

たとえ事例としてあってもベクトル化されてない書き方での重回帰分析のコードは見つかったのですが、ベクトル化した形で書いているものが見つからなかったです。

大規模なデータを扱う際や、変数が多い際はベクトル化して書かないと対応しきれないと思うので、スケールさせることを意識した書き方が重要だなと思いました。

実務的にはtensorflowで重回帰やるくらいならば、Rやscikit-learnを持ちいて行うほうが現実的だと思いますが、tensorflowの勉強のためにはこういったことをやるのもいいのかなと思います。

参考資料

Linear Regression in Tensorflow