回帰とは

前回は、教師なし学習の1つであるクラスタリングを扱い、機械学習の世界へと足を踏み入れました。教師なし学習では探索的にデータの規則性を見つけるのには適していますが、正解を定義することが難しく、あくまでも主観的な手法であることをお伝えしました。

そこで、今回からは正解データが用意されている教師あり学習に取り組んでいきます。第1回でも説明したように、教師あり学習は、「回帰」と、「分類」に分けられます。今回は、連続値の予測手法である「回帰」に挑戦していきましょう。

データの準備

連続値とは、売上、気温、家賃のように、数値として表現できるものです。今回は人口密度、総生産額、コンビニの数などから、家賃を予測してみましょう。データは、総務省統計局の統計データ、「社会生活統計指標-都道府県の指標-」から必要データを抽出したものを用意しました。

こちらから、データをダウンロードできます。まずは、前回と同様にデータを読み込んで眺めてみましょう。

ダウンロードしたCSVファイルをJupyter Notebookの作業フォルダ(MyNaviフォルダ)にコピーした後、Anaconda-NavigatorからJupyter Notebookを立ち上げてください。立ち上がったら、右上のNewから、Python3を選択し、Notebookを開き、左上のタイトルを適当なファイル名に変更しておきましょう。今回は、monthlyRent_regressionという名前にしました。

まずは、以下のコードを実行(shift+enter)してください。

import pandas as pd
allData = pd.read_csv('monthlyRent.csv')
allData

データ一覧

今回のデータ一覧を確認できましたでしょうか。実際に使用するのは、都道府県を除いた7つ(都道府県はラベル)になります。今回、家賃の予測を行いますが、こういった予測対象の変数を目的変数と呼び、それ以外の6つの変数のことを、説明変数と呼びます。

単位も記載していないので少しだけデータの説明をします。家賃は、厳密には民営賃貸住宅の家賃で、1カ月3.3m2当たりの価格です。1人暮らしの場合、20~30m2のため、単純に10倍すると少し大きめですが、よく見かける家賃の価格帯になると思います。人口密度に関しては、可住地面積1km2当たりの人口密度を選んでいます。県内総生産額、事業所数は、仕事に関する指標として抽出しており、県内総生産額は、単位が億円となっています。コンビニ数、飲食店数、病院数は、生活するうえでの利便性に関する指標として抽出しています。自分に関係のある都道府県の値を見てみましょう。

線形回帰に挑戦

さっそく、回帰に挑戦していくのですが、まずは、いくつかある説明変数の内、「人口密度」のみ用いて、家賃を予測してみましょう。今回も、散布図による可視化を行った後、回帰を行なっていきます。

まずは、可視化です。

import matplotlib.pyplot as plt
%matplotlib inline
plt.scatter(allData['人口密度'],allData['家賃'])
plt.xlabel('PopulationDensity')
plt.ylabel('MonthlyRent')

人口密度×家賃の散布図

実行すると、横軸に人口密度、縦軸に家賃のグラフが出力されます。ここまでのコードは、前回とほぼ同じで、1~2行目でグラフ描画ライブラリmatplotlibを使うための準備となります。それ以降の部分が散布図で描画するデータとラベルの指定となります。3行目のscatterのカッコ内において、「人口密度」と「家賃」を指定しています。

このグラフを見ると、人口密度が高くなると家賃も上がる(右肩上がり)傾向にあることがわかります。ちなみに、最も右上にあるのが、東京都のデータとなります。回帰とは、この右肩上がりの傾向を最もよく表現する線を引くこと(=学習)で、特に直線の場合は線形回帰と言います。それでは、実際に線形回帰を実行してみましょう。以下のコードを実行してみてください。

from sklearn.linear_model import LinearRegression
X1 = allData[['人口密度']]
Y1 = allData['家賃']
model1 = LinearRegression()
model1.fit(X1, Y1)

線形回帰

これで、線形回帰の学習が完了し、線を表現するモデルが作成されました。1~2行目で、機械学習ライブラリscikit-learn(sklearn)のなかから、LinearRegression、つまり線形回帰を呼び出しています。その後、説明変数として人口密度、目的変数として家賃を定義した後、線形回帰を実行しています。まずは、先ほどの散布図に、今回予測した線を追加して可視化してみましょう。

plt.scatter(allData['人口密度'],allData['家賃'])
plt.xlabel('PopulationDensity')
plt.ylabel('MonthlyRent')
plt.plot(X1, model1.predict(X1))

線形回帰の結果(直線の可視化)

右肩上がりの直線が表現できているのが確認できたでしょうか。線形回帰における学習とは、既知の家賃、人口密度データを教師データとして用いて、最も誤差の少ない直線を導き出すことなのです。この直線によって、人口密度から家賃を予測することが可能となりました。では試しに、人口密度が4000の場合の家賃を予測してみましょう。

model1.predict(4000)

線形回帰の結果(家賃の予測)

今回の学習で得たモデルによると、人口密度が4000の時は、家賃が5688になるという予測ができました。いろいろと数値を変化させて、家賃を予測してみましょう。

最後に、この直線の数式での表現と、モデルの評価について考えてみましょう。以下のコードを実行してみてください。

print(model1.coef_)
print(model1.intercept_)
print(model1.score(X1, Y1))

線形回帰の結果(係数および決定係数)

直線の式は、Y=aX + b で表現できるのを思い出してください。aを傾き、bを切片と呼びますが、1行目で傾き、2行目で切片を出力しています。つまり、家賃は、人口密度×0.5 + 3681で表現できるということを表しており、この値を教師データから機械に学習させたわけです。

前回と違い、今回はあらかじめ家賃がわかっている教師データから予測しています。そのため、今回学習によって作られた直線が正しいかどうかを評価することが可能です。最も単純に見る方法として、決定係数を見る方法があります。決定係数は、1に近づくほど、精度が高いことを表しており、今回のケースの0.769は比較的高い値で、人口密度を用いて家賃を上手く表現できていることを意味しています。ただし、実際には、決定係数だけでなく、残差プロット、平均2乗誤差、過学習に陥っていないか等も見る必要があります。今回は取り扱いませんが、過学習は次回以降に少しだけ取り扱う予定です。

変数を拡張して線形回帰に挑戦

これまでは、説明変数として人口密度のみを用いて線形回帰を行なってきました。しかし、これ以外にも変数を拡張することで、さらに上手に家賃を表現できる可能性があります。そこで、家賃を目的変数に、それ以外の6項目を説明変数にして回帰を実行してみます。先ほどのように、説明変数が1つの場合は、単回帰、複数ある場合は重回帰と呼びます。

まずは、データの準備を行います。

Y2 = allData['家賃']
X2 = allData.drop(['都道府県', '家賃'], axis=1)
X2.head()

重回帰データの準備

まず、目的変数として家賃を作成しました。さらに、都道府県、家賃の列を削除したX2を説明変数として作成しました。説明変数をhead()で出力すると、都道府県、家賃以外の6項目を確認できます。

それでは、さっそく、線形回帰を実行し、直線の数式での表現とモデルの評価まで一気に出力してみましょう。

model2 = LinearRegression()
model2.fit(X2, Y2)
print(pd.DataFrame({'係数名':X2.columns, '係数値':model2.coef_}))
print(model2.intercept_)
print(model2.score(X2, Y2)) 

重回帰

先ほどのモデルと区別するため、model2という名前でモデルを作成しました。fitによって、6つの変数と家賃を用いて線形回帰を実行しています。今回は、説明変数が6つあるため、係数も6つ存在します。つまり、Y=a1×[人口密度] + a2×[県内総生産額] + a3×[事業所数] + a4×[コンビニ数] + a5×[飲食店数] + a6×病院数 + bとなります。3行目に、6つの係数と係数名を一覧で表示しています。少し見にくいですが、3587が切片、最後の0.79が決定係数となります。これによって、6つの変数から家賃を予測することができます。決定係数もわずかに増加しており、若干モデルの精度が向上しています。

最後に、未知のデータから家賃の予測をしてみましょう。たとえば、人口密度4000、国内総生産額50000、事業所数100000、コンビニ数1000、飲食店数14000、病院数140の場合に家賃がいくらになるでしょうか。

X_pred = pd.DataFrame([[4000, 50000, 100000, 1000, 14000, 140]])
model2.predict(X_pred)

重回帰の結果(家賃の予測)

このモデルによると、家賃が5563になることがわかりました。それ以外にも、いろいろと試してみるとよいと思います。

可視化をしたいところですが、説明変数6つ、目的変数1つということは7次元であるため、どんな直線が引けているのかはグラフで表現できません。ただ、前回と違い教師データを持っているため、決定係数などによるモデル精度の評価が可能であり、客観的にモデルが正しいかどうかを判断することができるのが大きな長所となります。

さて、今回は、教師あり学習の回帰に挑戦してきました。教師データを用いて学習を行うということのイメージは湧きましたでしょうか。回帰は、今回取り扱った線形回帰以外にもいくつかありますが、今回用いた単回帰、重回帰を理解することで幅広い分野に応用できます。

さらに次のステップを試してみたい方にオススメなのが、新しい手法を覚えるのではなく、過去のデータから未来の予測に挑戦してみることです。今回は、過去の家賃、人口密度等のデータを教師データにして、未知の家賃を予測しましたが、これは未来の予測とは呼べません。未来を予測するためには、時系列も考慮する必要があります。たとえば、今月の野菜の出荷量から、来月の野菜の物価を予測するために、1カ月前の野菜の出荷量と今月の野菜の物価を教師データとして選択する必要があります。このように、教師データの取り方によって、予測できるものが変わってくるので、ぜひトライしてみてください。

次回からは、教師あり学習の分類を2回に分けて説明していきます。

著者プロフィール

下山輝昌
大手電機メーカーにて、ハードウェアの研究開発に従事した後、独立。独立後はソフトウェア、データ分析等において実務経験を積むとともに、数社を共同創業。その中でも合同会社アイキュベータでは、人工知能・IoTなどの可能性や方向性を研究している。最近では、オープンデータに着目し、オープンデータ活用のためのwebサービスの立ち上げ、オープンデータ×IoTによる価値創出を1つのテーマに取り組んでいる。