SEワンタンの独学備忘録

IT関連の独学した内容や資格試験に対する取り組みの備忘録

【Python】入門⑰ Pythonで学ぶ「教師あり学習」 回帰編(多次元モデル)

線形回帰モデルではこれまで最も基本的な一次元入力と二次元入力を扱ってみましたが、今回は多次元(N次元)線形回帰モデルを扱います。

入力の次元数を限定しないことによって、本格的な活用も可能になってくるかと思います。
煩雑になってくるかもしれませんが、一つの区切りとなるので頑張ります。

N次元線形回帰モデル

N次元線形回帰モデル(重回帰分析)

少し数学的な話が続くので辛い。

最初は入力パラメータが1次元で直線モデル、次に二次元になって面モデル、次元が増えたときにモデル自体が命名されているのかは分かりませんが、これは全て線形回帰モデルです。

・直線モデル
f:id:wantanBlog:20200202012612p:plain

・面モデル
f:id:wantanBlog:20200202012649p:plain

これらから線形回帰モデルはN次元で一般化して以下のように表現することが可能です。
このように入力パラメータがNになる回帰分析のことを重回帰分析と呼ぶらしいです。

・線形回帰モデル
f:id:wantanBlog:20200202012951p:plain

モデルのパラメータ解析解(単純化モデル)

解析解とは数学的に導出した解(w)のことです。
N次元モデルの解析解について考えていきますが、まずは単純化して線形モデルの切片を排除して考えていきます。

f:id:wantanBlog:20200202020027p:plain

このとき、行列表記を用いるとこのモデルは以下のように表現することができます。

f:id:wantanBlog:20200202021303p:plain


ここから実際に平均二乗誤差Jを導出していきます。
平均二乗誤差は今まで通り以下の式を使用します。

f:id:wantanBlog:20200202171923p:plain

これまでと同様にwの解を求めるには偏微分を行います。
次元が低かった場合は実際にw0やw1の偏微分を求めることができましたが、N次元の場合は一つ一つ求めることができませんので一般化して求めます。

f:id:wantanBlog:20200202172840p:plain


平均二乗誤差Jが最小になる値を求めるには、偏微分の結果がゼロになる場合の連立方程式を解くのでした。

f:id:wantanBlog:20200202175502p:plain

しかし、このままでは導出が困難なので、行列(ベクトル)を用いて導出します。

f:id:wantanBlog:20200202180555p:plain

f:id:wantanBlog:20200202180854p:plain

飛ばし気味になりますが、この式を展開します。

f:id:wantanBlog:20200202181412p:plain

ここで、さらに単純化するために係数となる2/Nを排除するためにN/2を両辺に乗算し、行列式で置換します。

f:id:wantanBlog:20200202181825p:plain


行列やベクトルなどを急にだしたので、少し整理しておきます。

f:id:wantanBlog:20200202184104p:plain


先に示した行列式の中身は上記の式の通りとなっています。

ここからwを求めるための式を導出していきます。

f:id:wantanBlog:20200202185546p:plain


wの項以外を右側に移行し、逆行列を左から乗算することによってwを求めることができます。

f:id:wantanBlog:20200203231019p:plain


このwの式は入力パラメータとなるxが何次元であっても適用できます。
ちなみに右辺の式には「ムーア・ペンローズの擬似逆行列」という名前がついているらしいです。

モデルのパラメータ解析解

今導出したwの式は単純化した式だったので、次に正式な式で導出を行います。
正式な式とは単純化するために取り去った切片を付けた状態のことです。

線形回帰モデルは元々以下のような式でした。

f:id:wantanBlog:20200203233524p:plain

ここで切片の項にxを加えることで行列として考えられるように拡張します。
このときのxは「1」とすることで元の式と同様の式とみなすことができます。

f:id:wantanBlog:20200203233828p:plain

この式を用いると平均二乗誤差を求めるときに「N-1」までではなく「N」までの和を求めるようにして同様の導出を行うことで再現できます。

f:id:wantanBlog:20200203234623p:plain

Pythonライブラリを用いた重回帰分析

だいぶ苦しくなってきたのでPythonライブラリを実装で濁します。
以下を参考にさせていただきました。

scikit-learn で線形回帰 (単回帰分析・重回帰分析) – Python でデータサイエンス

scikit-learnライブラリを用いた単回帰分析

今回はscikit-learnライブラリを用いますが
まずは使用方法を確認するために単回帰分析を行います。

データは下記記事で用いた単純なXとYの分析になります。

www.wantanblog.com

・例

# sklearn.linear_model.LinearRegression クラスを読み込み
from sklearn import linear_model
import pandas as pd
import numpy as npy
import matplotlib.pyplot as plt

clf = linear_model.LinearRegression()

# データをblog_data.npzファイルから取り出す
sample_data = npy.load('blog_data.npz')

X = sample_data['X']
X = npy.array([X]).T
Y = sample_data['Y']

# 予測モデルを作成
clf.fit(X, Y)
# 回帰係数
print(clf.coef_)
# 切片 (誤差)
print(clf.intercept_)
# 決定係数
print(clf.score(X, Y))

# 散布図
plt.scatter(X, Y)
# 回帰直線
plt.plot(X, clf.predict(X))

・出力結果

[0.61743692]
-130.73081352003646
0.9831086573905393

f:id:wantanBlog:20200205000122p:plain

以前、ライブラリを用いた導出と同様の結果になりました。

重回帰分析

ここでやっと本題に入ります。
データは毎度おなじみのGoogleアナリティクスからとってきたブログに関連するデータを使用します。

今回は以下のような複数のパラメータをCSV形式で用意してある値に関する他のパラメータの相関を見ていきます。

f:id:wantanBlog:20200205004612p:plain

・例

# sklearn.linear_model.LinearRegression クラスを読み込み
from sklearn import linear_model
clf = linear_model.LinearRegression()
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

blogdata = pd.read_csv("monthly_repo.csv", sep=",")
# 対象外の項目を除く
except_values = blogdata.drop("Ad", axis=1).drop("month", axis=1)
X = wine_except_quality.as_matrix()
Y = blogdata['Ad'].as_matrix()
 
# 予測モデルを作成
clf.fit(X, Y)
 
# 偏回帰係数
print(pd.DataFrame({"Name":except_values.columns,"Coefficients":clf.coef_}))
 
# 切片 (誤差)
print(clf.intercept_)

・出力結果

       Name  Coefficients
0  pageview     -0.004414
1     users     -0.225594
2  new_user      0.249534
3  pagetime     -0.007337
4    bounce     11.436902
5   session     -0.007255
-4.730505205297209

こいつらがなにを表しているのか考えることが重要です。
今算出された値が重みwです。なので以下の式の各wに上記で算出した値を当てはめることで、本ブログに関する線形回帰モデルが生成できたことになります。

ちなみに各xはパラメータで、最後のWnが切片です。

f:id:wantanBlog:20200202012951p:plain


最後にリンク先の記事をまねて各パラメータの結果への影響度を測っておきたいと思います。

・例

# sklearn.linear_model.LinearRegression クラスを読み込み
from sklearn import linear_model
clf = linear_model.LinearRegression()
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

blogdata = pd.read_csv("monthly_repo.csv", sep=",")
# データフレームの各列を正規化
blogdata2 = blogdata.apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x)))

# 対象外の項目を除く
except_values = blogdata2.drop("Ad", axis=1).drop("month", axis=1)
X = except_values.as_matrix()
Y = blogdata2['Ad'].as_matrix()
 
# 予測モデルを作成
clf.fit(X, Y)
 
# 相関値
print(pd.DataFrame({"Name":except_values.columns,"Coefficients":npy.abs(clf.coef_)}))
 
# 切片 (誤差)
print(clf.intercept_)

・出力結果

       Name  Coefficients
0  pageview      3.755232
1     users    118.060812
2  new_user    126.898203
3  pagetime      0.126866
4    bounce      0.619499
5   session      4.637096
-3.610323004487209e-15

本ブログの場合はユーザ数、新規ユーザ数が大きく影響を及ぼしているようです。
なんとなくは分かるけど、それならページビュー数とかセッション数も高くなりそうなものだけどなんでそうはならないんだろうか?
その辺は今後探れるようになれたらと思います。

・今回のソース
python_dev/Supervised_learning4.ipynb at master · wantanblog/python_dev · GitHub