機械学習入門

【機械学習入門②】線形回帰・単回帰モデルをPythonの実装付きで理解!

機械学習 入門② 線形回帰 単回帰モデル

 

前回の記事『【機械学習入門①】初心者でも分かる機械学習の概要と4つの分類』では、機械学習の概要について触れました。

 

今回は、具体的な機械学習手法の1つである線形回帰・単回帰モデルに触れていきたいと思います。

この記事で学べる内容は、以下のとおりです。

  • 単回帰モデルについて
  • 単回帰モデルの実装方法

 

線形回帰の単回帰モデルは、教師あり学習の「回帰」で一番基本的なモデルです。

単回帰モデルをおさえておくと、機械学習のイメージが一気に膨らむようになるので、丁寧に学習していきましょう。

 

この記事について

この記事は、機械学習を体系的に学べる「機械学習入門講座」の1つです。

 

機械学習を勉強しようと思ったとき、以下のような悩みを持ったことはないですか?

  • 機械学習を学んでみたいけど、何から勉強したら良いのか分からない
  • 機械学習の本を買ってみたけど、よく分からなくて挫折した
  • そもそも本を買うのではなく、まずは「無料」で学習してみたい

上記のような、「機械学習を勉強し始める前の悩み」を解決するために、この機械学習講座を作成しました。

 

「プログラミングスクールは高いし、参考書は途中で飽きちゃうし…」といった方は、ぜひ第1回から学習して頂けたらと思います(*’ω’*)

一覧ページへ≫

線形回帰・単回帰モデルとは?

 

線形回帰・単回帰モデルとは、あるデータ\(x\)から対象\(y\)を予測することです。数式で表すと、以下のようになります。

$$y = w_0 + w_1 x_1$$

よく見ると、中学生のときに習った一次関数\(y = ax + b\)の形をしていますよね。

つまり、線形回帰・単回帰モデルとは、直線を使って変数\(x\)から対象\(y\)を予測することです。

 

たとえば、\(x\)と\(y\)を以下のようにしましょう。

  • \(x\) : 気温
  • \(y\) : アイスクリームの売上個数

具体的な数字も入れると、こんな感じになるかと思います。

気温アイスクリームの売上
2810
269
204
247
225

 

これを図で表すと、以下のようになります。

散布図 アイスクリーム

実際に可視化してみると分かりますが、なんとなく“右肩上がりの直線”が引けそうですよね。

この「直線を使って予測する」のが単回帰モデルです。

 

実際には、完璧に直線で表すことはできないので、各点からなるべく近い位置を通る直線を引くことになります。

そして、各点からなるべく近い位置を通る直線を求めるのに必要なアクションは、\(y = w_0 + w_1 x_1\)の”\(w_0\)”と”\(w_1\)”を求めることです。

※この「各点からなるべく近い位置を通る直線」の理論を近いするには、ちょっと数式の理解が必要になります。

具体例で考える単回帰モデル

 

Pythonの機械学習ライブラリscikit-learnに入っている『ボストン住宅価格データセット』を使って、具体的に考えてみます。

 

ボストン住宅価格データセットの中身

『ボストン住宅価格データセット』には、以下のデータが入っています。

変数名データの説明
CRIM犯罪発生率
ZN住居区画の密集度
INDUS非小売業の土地割合
CHASチャールズ川の周辺か否か
NOXNOx濃度
RM住居に含まれる平均部屋数
AGE1940年より前に建てられた物件の割合
DISボストン市の5つの雇用施設からの重み付き距離
RAD大きな道路へのアクセスのしやすさ
TAX1万ドルあたりの不動産税率の総計
PTRATIO教師あたりの生徒数
B対象地域に住む黒人の比率
LSTAT低所得者の割合

 

たとえば、『住居に含まれる平均部屋数=RM』と予測対象の『住宅価格=MEDV』を、散布図で確認してみます。

ボストン住宅価格 散布図

図で確認すると、なんとなく右肩上がりの直線で予測できそうですね。

感覚的にも、部屋の数が増えれば、住宅価格は上がる気がします。

 

このとき、”各点になるべく近い位置を通る直線”は、以下の式で表せますね。

$${\rm MEDV} = w_0 +  w_1 {\rm RM}$$

これが単回帰モデルです。

 

実際に”各点になるべく近い位置を通る直線”を引くには、現段階で分かっていない\(w_0\)と\(w_1\)を求めてあげることになります。

以下が完成イメージです。

単回帰モデル イメージ

 

他にも、以下のような予測で、単回帰モデルを活用できます。

  • 江ノ島で遊んでいる人を、気温で予測する
  • 満員電車の乗車率を、時刻で予測する
  • 寿命を、年齢で予測する

 

線形回帰の「線形」とは?

 

今回学習する単回帰モデルや、次回扱っていく重回帰モデルは「線形」です。

たとえば、以下で表される数式も「線形」です。

$$y = \sum_{i=1}^{n} w_i x_i$$

 

\(\sum\) はシグマといって、”足し合わせる”という意味の記号です。

なので、シグマを外すと、以下のような式になります。

$$y = w_1 x_1 + w_2 x_2 + \cdots + w_n x_n \tag{1}$$

そして、この式の\(n = 2\) で \(x_1 = 1\) の場合が「単回帰モデル」の式になります。

 

「線形」の細かい定義は少し難しいので省略してOKです。

ざっくりしたイメージでいうと、単回帰モデルを含む、式(1)の形で表せる数式は線形になります。

 

式(1)が線形になる理由

 

少し難しいので、スキップしても大丈夫な部分です。

 

「線形」の定義は、以下を満たす数式になります。

  • ①\(f(x+y)=f(x)+f(y)\)
  • ②\(f(kx)=kf(x)\) (\(k\):実数)

上記を満たす場合、その数式を線形と呼びます。

 

実際に\(f(x) = \displaystyle \sum_{i=1}^{n} w_i x_i\)が線形になるのか確認してみます。

①\(f(x+y)=f(x)+f(y)\)の場合

 

$$
\begin{eqnarray}
f(x + y) &=& w_1 (x_1 + y_1) + w_2 (x_2 + y_2) + \cdots + w_n (x_n + y_n)\\
&=& w_1 x_1 + w_1 y_1 + w_2 x_2 + w_2 y_2 + \cdots + w_n x_n + w_n y_n\\
&=& (w_1 x_1 + w_2 x_2 + \cdots + w_n x_n) + (w_1 y_1 + w_2 y_2 + \cdots + w_n y_n)\\
&=&f(x) + f(y)
\end{eqnarray}
$$
上記のように式展開してあげれば、①の条件が成り立ちますね。

 

②\(f(kx)=kf(x)\) (\(k\):実数)の場合

 

$$
\begin{eqnarray}
f(kx) &=& w_1 (k x_1) + w_2 (k x_2) + \cdots + w_n (k x_n)\\
&=& k w_1 x_1 + k w_2 x_2 + \cdots + k w_n x_n\\
&=& k(w_1 x_1 + w_2 x_2 + \cdots + w_n x_n )\\
&=& kf(x)
\end{eqnarray}
$$

こちらも同様に、丁寧な式展開をすれば、条件②を満たしていることが分かります。

 

なので、単回帰モデルを含む\(f(x) = \displaystyle \sum_{i=1}^{n} w_i x_i\)は、線形になります。

※ちなみに、単回帰モデルは\(n=2\)の場合ですが、\(n \geq 3\)の場合を重回帰モデルと言います。詳細は次回解説しますが、上の証明により重回帰モデルも線形になります。

機械学習入門④ 線形回帰 重回帰モデル
【機械学習入門④】線形回帰・重回帰モデルをPythonの実装付きで理解! 前回の記事『【機械学習入門③】最小二乗法とは?手計算とPythonを使った実装を解説【初心者向け】』では、単回帰モデルの導出方法...

Pythonを使った単回帰モデルの実装方法【Scikit-learn】

機械学習入門② 線形回帰 Python

 

単回帰モデルの概要が分かったところで、さっそく実装をしていきましょう。

実装は以下の手順で進めていきます。

  • STEP① : ライブラリの読み込み
  • STEP② : データの読み込み
  • STEP③ : データの準備
  • STEP④ : 単回帰モデルの作成と評価

 

コードは以下のとおりです。

# ## 2. 線形回帰・単回帰モデルの実装

# ### 2.1 ライブラリの読み込み
import numpy as np
import pandas as pd

from sklearn.datasets import load_boston
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

import matplotlib.pyplot as plt
import seaborn as sns

sns.set()
sns.set_style("ticks")

# ### 2.2 データの読み込み
boston = load_boston()
df = pd.DataFrame(boston.data, columns=boston.feature_names)
df['MEDV'] = boston.target

print(df.head())

# 可視化
plt.figure(figsize=(10, 6))
sns.scatterplot(x=df.RM, y=df.MEDV, alpha=0.7)
plt.show()

# ### 2.3 データの準備
x = df['RM']
X = np.array(x).reshape(-1, 1)
y = df['MEDV']

print('-'*10 + '特徴量とターゲットに分割' + '-'*10)
print('X:', X.shape)
print('y:', y.shape)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

print('元データ', X.shape)
print('学習用データ', X_train.shape)
print('テスト用データ', X_test.shape)

# ### 2.4 単回帰モデルの作成と評価
lm = LinearRegression()
lm.fit(X_train, y_train)

print('Train Score:{:.2f}' .format(lm.score(X_train, y_train)))
print('Test Score:{:.2f}' .format(lm.score(X_test, y_test)))
print('バイアス', lm.intercept_)
print('重み', lm.coef_)

# ### 2.5. 学習結果の可視化
y_pred = lm.predict(X_test)

plt.figure(figsize=(10, 6))
sns.scatterplot(X.reshape(len(X), ), y, alpha=0.7)
sns.lineplot(x=X_test.reshape(len(X_test), ), y=y_pred, linewidth=3, label='Simple Regression Model')
plt.xlabel('RM')
plt.ylabel('MEDV')
plt.show()

ちょっと長くなっていますが、それはグラフを出力しているからです。

機械学習だけだったら、20行くらいで実装できますよ!

 

STEP① : ライブラリの読み込み

import numpy as np
import pandas as pd

from sklearn.datasets import load_boston
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

import matplotlib.pyplot as plt
import seaborn as sns

sns.set()
sns.set_style("ticks")

 

まずは、今回必要になるライブラリをインポートします。

  • Numpy : 配列計算用ライブラリ
  • Pandas : データ操作用ライブラリ
  • Scikit-learn(sklearn) : データの準備・機械学習モデルの作成用ライブラリ
  • Matplotlib : 作図用ライブラリ①
  • Seaborn : 作図用ライブラリ②

 

STEP② : データの読み込み

boston = load_boston()
df = pd.DataFrame(boston.data, columns=boston.feature_names)
df['MEDV'] = boston.target

print(df.head())

# 可視化
plt.figure(figsize=(10, 6))
sns.scatterplot(x=df.RM, y=df.MEDV, alpha=0.7)
plt.show()

 

次に、単回帰モデルで使う『ボストンの住宅価格データセット』を読み込みます。

 

再掲 : ボストン住宅価格データセットの中身

変数名データの説明
CRIM犯罪発生率
ZN住居区画の密集度
INDUS非小売業の土地割合
CHASチャールズ川の周辺か否か
NOXNOx濃度
RM住居に含まれる平均部屋数
AGE1940年より前に建てられた物件の割合
DISボストン市の5つの雇用施設からの重み付き距離
RAD大きな道路へのアクセスのしやすさ
TAX1万ドルあたりの不動産税率の総計
PTRATIO教師あたりの生徒数
B対象地域に住む黒人の比率
LSTAT低所得者の割合

 

上記のように、たくさん変数がありますが、今回はRM(=住宅に含まれる平均部屋数)を使って、MEDV(=住宅価格)を予測しましょう。

散布図を使って可視化しておくと、以下のようになります。

ボストン住宅価格 散布図

ちなみに、df.head()はデータの上から5行を、Excelのようにキレイな形で出力するコマンドです。

ボストン住宅価格 データフレーム

上記のように、かなり中身を確認しやすい形で出力してくれます。

 

STEP③ : データの準備

x = df['RM']
X = np.array(x).reshape(-1, 1)
y = df['MEDV']

print('-'*10 + '特徴量とターゲットに分割' + '-'*10)
print('X:', X.shape)
print('y:', y.shape)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

print('元データ', X.shape)
print('学習用データ', X_train.shape)
print('テスト用データ', X_test.shape)

 

それでは、単回帰モデルの実装で必要なデータの準備をしていきます。

特徴量(=機械学習で使う変数)はRM、予測対象はMEDVです。

数式で表すと、以下のようになりますね。

$${\rm MEDV} = w_0 +  w_1 {\rm CRIM}$$

 

train_test_split()では、訓練用データとテスト用データの分割をしています。

この分割をしないと、単回帰モデルを作りっぱなしになってしまい、作成されたモデルの良し悪しが分かりません。

 

テストデータを残しておくことで、後からモデルの性能を評価します。

test_size=0.2にしているので、学習データ:テストデータ=8:2になります。

  • 元データ : 506
  • 学習用データ : 404
  • テスト用データ : 102

これが今回使うデータの大きさです。

 

STEP④ : 単回帰モデルの作成と評価

lm = LinearRegression()
lm.fit(X_train, y_train)

print('Train Score:{:.2f}' .format(lm.score(X_train, y_train)))
print('Test Score:{:.2f}' .format(lm.score(X_test, y_test)))
print('バイアス', lm.intercept_)
print('重み', lm.coef_)

 

単回帰モデルを使うには、LinearRegression()を使います。

そして、モデルの学習はlm.fit()を使うだけです。

 

ボストン住宅価格のデータ量は、そこまで多くないので、実行するとすぐに結果が出ます。

 

学習結果を見てみましょう。

lm.score()を使えばモデルの決定係数を確認できます。

print('Train Score:{:.2f}' .format(lm.score(X_train, y_train)))
print('Test Score:{:.2f}' .format(lm.score(X_test, y_test)))
  • Train Score:0.50
  • Test Score:0.42

決定係数は、0〜1の値を取り、1に近い方が精度が良いという解釈になります。

なので、今回作成したモデルは、そこまで良いモデルだとは言えないですね。

 

ちなみに、「良い単回帰モデルを作成する」とは、単回帰式\(y = w_0 + w_1 x_1\)に含まれる、\(w_0\)と\(w_1\)で最適な値を求めることになります。

つまり、Scikit-learnを使って単回帰モデルを作成すると、\(w_0\)と\(w_1\)が求まっています。

※ライブラリを使って計算しているので中身は見えませんが、実は色々なロジックに基づいて最適な\(w_0\)と\(w_1\)を計算しています。

print('バイアス', lm.intercept_)
print('重み', lm.coef_)
  • バイアス -36.47618962764734
  • 重み [9.37638431]

バイアスと呼んでいるのが、\(w_0\)、重みと呼んでいるのが\(w_1\)です。

数式で表すと、以下のようなモデルが完成したことになります。

$$y = -36.476 + 9.3764 x$$

 

今回、\(x\)がRM、\(y\)がMEDVだったので、要するに以下のような式になりますね。

$${\rm MEDV} = -36.476 + 9.3764 {\rm RM}$$

 

STEP⑤ : 学習結果の可視化

 

機械学習を実装する手順ではないですが、学習結果の可視化もやっていきましょう。

やはり目に見えて確認できた方が、実感が湧きます。

 

可視化のコード

y_pred = lm.predict(X_test)

plt.figure(figsize=(10, 6))
sns.scatterplot(X.reshape(len(X), ), y, alpha=0.7)
sns.lineplot(x=X_test.reshape(len(X_test), ), y=y_pred, linewidth=3, label='Simple Regression Model')
plt.xlabel('RM')
plt.ylabel('MEDV')
plt.show()

 

上記を使うと、元データと学習結果を可視化できます。

単回帰モデル 結果

 

だいたい予測できていますが、中には全く予測できていないデータもありますね。

このように、単回帰モデルはシンプルかつ直感的に分かりやすいモデルではありますが、そこまで正確に予測できるモデルではありません。

【機械学習入門②】単回帰モデルまとめ

 

というわけで、今回は以上です。

線形回帰・単回帰モデルについて、理解できたのではないでしょうか。

 

ただ、今回の講義では、単回帰モデルを作成するとき、”各点からなるべく近い位置を通る直線を求める”と解説していました。なので、実際にどうやって導出するのか、分からない状況です。

 

次回は、単回帰モデルの導出方法である「最小二乗法」について学習していきます。

機械学習入門③ 最小二乗法
【機械学習入門③】最小二乗法とは?手計算とPythonを使った実装を解説【初心者向け】『最小二乗法ってなんだろう...。計算方法からPythonの実装まで、丁寧に解説されている記事はないかな...。』このような悩みを解決する記事になっています。最小二乗法について知りたい方は必見です。...

 

最小二乗法を理解しておくと、機械学習モデルの導出方法イメージが、かなり鮮明になります。

数式の解説が少し多いですが、かなり丁寧に書いているので、初学者でも安心して学べますよ。

 

この記事が良いと思ったら、ぜひ次の『【機械学習入門③】最小二乗法とは?手計算とPythonを使った実装を解説【初心者向け】』も学んで頂けたらと思います(*’ω’*)

 

なお、『機械学習入門シリーズ』は長いので、休みながら学習を進めてみてくださいね。

休憩するときは、記事をツイートしておくと便利ですよ!

※メンションに気が付いたら、拡散する可能性高いです(`・ω・´)!

 

それでは、この辺で。

 

おすすめの記事

機械学習入門③ 最小二乗法
【機械学習入門③】最小二乗法とは?手計算とPythonを使った実装を解説【初心者向け】『最小二乗法ってなんだろう...。計算方法からPythonの実装まで、丁寧に解説されている記事はないかな...。』このような悩みを解決する記事になっています。最小二乗法について知りたい方は必見です。...