分類とは
前回は、教師あり学習のなかでも連続値の予測手法である「回帰」に触れ、説明変数である人口密度、総生産額、コンビニの数などから、目的変数の家賃を予測することに挑戦しました。教師データを使い学習するプロセスは理解できましたでしょうか。
今回からは、予測する目的変数が離散値である教師あり学習「分類」に挑戦していきます。機械学習の分類は多くの場面で活用されます。簡単な事例だと、「スパムメールなのか、そうでないか」、「課金してくれる顧客なのか、そうでないか」のような2値の分類が挙げられます。また、2値分類だけではなく、多クラス分類も存在し、アヤメの種類を花弁の長さや幅等から3種類に分類する例等が挙げられます。
今回は、分類の代表的な手法である決定木を用いて、2値の分類に取り組んでいきます。また、教師あり学習を行ううえでは避けて通れない、過学習にも触れていきたいと思います。
データの準備
今回は、第3回の教師なし学習の際に用いた各都道府県の物価データを説明変数として、「大都市圏を持つ都道府県なのか、そうでないか」を目的変数として分類してみます。決定木を用いて機械学習モデルを作成することで、どんな物価の場合が大都市圏として認定されるのかどうかを予測できるようになります。
データは第3回と同じく政府統計の総合窓口e-statの消費者物価地域差指数をダウンロードし、必要なデータを抽出しました。さらに、今回は教師あり学習なので、平成27年の国勢調査時に定められた大都市圏を参考に、大都市圏中心市を含む都道府県にフラグを代入し目的変数データを用意しました。こちらからデータをダウンロードできます。
まずは、これまでと同様にデータを読み込んで眺めてみましょう。ダウンロードしたCSVファイルをJupyter Notebookの作業フォルダにコピーした後、Jupyter Notebookを立ち上げてください。立ち上がったら、右上のNewから、Notebookを開き、タイトル名に変更しておきましょう。今回は、ConsumerPrices_treeという名前にしました。
まずは、以下のコードを実行してください。
import pandas as pd
data = pd.read_csv('consumerPrices_tree.csv')
data
データ一覧を確認できましたでしょうか。最後の大都市圏分類という項目以外は、第3回に用いたものとまったく同じで、都道府県別に、10個の項目における物価指数が入っています。全国平均が100となっています。大都市圏分類は、上述したように、大都市圏中心市を持つ都道府県には1が、それ以外は0が入っていることが確認できると思います。
大都市圏に分類されたデータがいくつかあるか確認しておきましょう。
data['大都市圏分類'].value_counts()
0が31個、1が16個存在することが確認できました。このデータを教師データとして、決定木を用いて分類を行っていきます。
決定木
決定木は、2値もしくは多クラスを分類する際に有効な手法で、機械による分類の過程を非常に直感的に理解することができます。そのため、機械学習本来の目的である未知なデータの予測以外にも、予測に寄与している要因の探索などにも活用できます。決定木の詳細は割愛しますが、端的に言うと、最も綺麗に0と1を分割できる説明変数およびその条件を探す作業を、木構造状に派生させていく手法です。
早速、データの準備を行った後、決定木をやっていきましょう。
X = data.drop(['都道府県', '大都市圏分類'], axis=1)
Y = data['大都市圏分類']
X.head()
これによって、説明変数として物価のデータが、目的変数として大都市圏分類が用意されました。目的変数が1/0の2値ではありますが、教師データとして説明変数X、目的変数Yを用意する点は、前回の回帰とまったく同じです。
次に決定木を実行してみましょう。
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier(max_depth=3, random_state=0)
model.fit(X, Y)
model.predict(X)
これで、決定木の学習から予測までが完了しました。1行目で機械学習ライブラリscikit-learn(sklearn)のなかから、DecisionTreeClassifier、つまり決定木を呼び出しています。2行目でmodelという名前で決定木を使う宣言をしています。モデルの条件として、max_depth、random_stateを渡しています。詳細は後述しますが、木の深さ(max_depth)として3階層目までを与えています。3行目で、教師データを先ほど宣言したモデルに代入して、学習を実行し、機械学習モデルを作成しています。最後に、説明変数Xをモデルに代入し、予測値を出力しています。この予測値が、目的変数Yとぴったり一致すれば予測の的中率が100%ということになります。
比較のために少しデータを整えて表示してみましょう。
predicted = pd.DataFrame({'Predicted':model.predict(X)})
data_predicted = pd.concat([data, predicted], axis =1)
data_predicted
このデータの大都市圏分類が正解のデータで、今回のモデルによって予測した値がPredictedに入っています。上から見ていくと、北海道はうまく予測できていますが、宮城はうまく予測できていないことがわかります。では、精度を数字で出力してみましょう。
sum(model.predict(X)==Y)/len(Y)
全データ数を分母に、教師データと予測データが一致したデータ数を分子にして、計算したところ正答率は87%程度となりました。
予測に寄与している変数
次に、予測に寄与している変数を確認するために、決定木の代名詞、木構造を可視化しますが、少しいくつか設定も必要なため、今回は、紹介するに留めます。興味のある方は、決定木、Graphviz等を調べてみてください。
こちらが、先ほど予測したモデルの木構造であり、決定木が直感的にわかりやすいと言われている所以です。機械が分類したプロセスの最初は、一番上の教養娯楽が99.85以下なのかどうかで分類しています。その結果、99.85より大きい場合は9個の都道府県が、class=1、つまり大都市圏に分類できることがわかります。次に、教養娯楽が99.85以下の38都道府県のなかで、保険医療が99.35以下なのかを分類した際、99.35以下の場合、14個の都道府県がclass=0に綺麗に分けられるということです。
決定木のモデルを宣言する際に、max_depth=3としましたが、それはまさに、分岐が3階層という意味です。当然、この深さを深くすると、より分岐が増え、複雑なモデルを作成することができます。機械学習モデルを作るというのは、この図からわかるように、どういった分岐をさせれば良いかを決めることです。この分岐条件を学習によって決定することで、未知なデータが来た際にも、分類することが可能になります。
さて、この木構造を見ると、教養娯楽、保険医療のみしか説明変数が出てきていません。これは、珍しいケースで、10項目ある説明変数のうち、ほぼこの2項目で分類が可能であることを示しています。では、変数の重要度を見てみましょう。
importance = pd.DataFrame({ '変数':X.columns, '重要度':model.feature_importances_})
importance
1行目で、変数名と機械学習モデルの変数重要度を抽出し、2行目で出力しています。model.feature_importances_の部分が、今回のモデルの変数重要度を呼び出している部分となります。この結果も、先ほどの木構造と同様、教養娯楽、保険医療以外は寄与していないのがわかります。今回のモデルにおいては教養娯楽、保険医療の物価が大都市圏を持つ都道府県なのかどうかを分類する際の鍵を握っているようで、特に教養娯楽の物価が高い傾向にあると大都市圏を持つ都道府県の可能性が高いようです。
過学習
さて、決定木による機械学習モデルを作成後、精度として87%を算出しましたが、この値がモデルの精度を表せているのかを考えてみましょう。
ここで算出した精度は、学習に用いたデータを使って予測を行っているため、複雑なモデルを作成すれば、当然ながら正答率は高くなります。本来、機械学習は未知なデータに対して正しく予測できることが目的です。では、どのようなモデル評価を行なっていくのが良いのでしょうか。
正しくモデル評価を行うためには、あらかじめデータを、訓練データとテストデータに分割し、訓練データでモデルを作成した後、学習に用いていないテストデータを用いてモデル評価を行うのが一般的です。手っ取り早くデータを分割するには機械学習ライブラリscikit-learn(sklearn)のなかのtrain_test_splitを用いるのが有効です。
from sklearn.model_selection import train_test_split
X_train,X_test,Y_train,Y_test = train_test_split(X, Y,random_state=0, test_size=0.3)
X_train
1行目で、train_test_splitを読み込んでいます。2行目でデータの分割を行い、説明変数X、目的変数Yをそれぞれ訓練データ、テストデータに分割しています。test_size=0.3として、全データの30%をテストデータとしています。
では、先ほどと同じ条件で決定木を実行し、モデルの予測まで行なって見ましょう。
model = DecisionTreeClassifier(max_depth=3, random_state=0)
model.fit(X_train, Y_train)
from sklearn import metrics
print(metrics.accuracy_score(Y_test, model.predict(X_test)))
print(metrics.accuracy_score(Y_train, model.predict(X_train)))
1行目、2行目は、先ほどと同じ条件での決定木によるモデル作成となります。3行目は、先ほど算出した精度と同じ計算を簡単に実行するためにmetricsをimportしています。これによって、目的変数Yの正解データと、モデルで予測した値を比較して、正答率を算出してくれます。4行目はテストデータを用いた際の正答率で、5行目は訓練データを用いた際の正答率となります。
これを見ると、訓練データでは97%近い精度が出ていますが、テストデータにした途端、66%程度にまで精度が下がっています。今回のケースのように、訓練データにモデルがFitしすぎているケースは過学習であると考えられます。過学習の場合、モデルの一般性が失われ、未知のデータに対して良いモデルとは言えません。いくつかパラメータを最適化することで、過学習傾向を脱し、モデルを汎化させることができます。しかし、今回のデータではそもそもデータ数が47個と少ないため、できることが限られてきます。そのため、今回は、モデルの複雑さがモデルにどう影響するかの確認のみを行なっておきましょう。
決定木の場合、max_depthを大きくすると、階層が増えるため、よりモデルが複雑になっていきます。まずは、max_depthを1に設定し、モデルを簡易化してみましょう。
model = DecisionTreeClassifier(max_depth=1, random_state=0)
model.fit(X_train, Y_train)
print(metrics.accuracy_score(Y_test, model.predict(X_test)))
print(metrics.accuracy_score(Y_train, model.predict(X_train)))
訓練データの数字が先ほどよりも少し下がったのが確認できたでしょうか。
では、続けて、モデルを複雑な方向に変えてみます。
model = DecisionTreeClassifier(max_depth=5, random_state=0)
model.fit(X_train, Y_train)
print(metrics.accuracy_score(Y_test, model.predict(X_test)))
print(metrics.accuracy_score(Y_train, model.predict(X_train)))
こちらは、逆に訓練データの精度が先ほどよりも増加し、100%の精度が出ています。しかし、テストデータの精度は上がっておらず、単純にモデルを複雑化しても、訓練データをよく表現できているモデルに過ぎません。
今回は、データ数が少ないため、深くは議論できませんが、良いモデルは、訓練データとテストデータの精度が近い値を示し、かつ精度が高いモデルを指します。訓練データの精度が高く、テストデータの精度が低い場合は、過学習傾向にあり、モデルの複雑さを減らしたり、データを増やしたりすることで解決できる場合があります。常に、モデルの目的を考え、精度に踊らされないようにしていくことが重要です。
さて、今回は、教師あり学習の分類(決定木)に挑戦しつつ、モデルの評価や過学習に関して取り扱ってきました。前回よりも一歩進んだ機械学習の世界に触れることができたかと思います。
ここまでやったことを思い返すと、機械学習のモデルを作る作業は数行で書くことができ、非常に簡単だったかと思います。しかし、最も重要なのは、ちょっと触って見てモデルが作れた、ではなく、今回の最後に取り扱ったモデルの精度検証に真摯に向き合っていくことだと思います。精度検証やデータ分割はいろんな手法があるので、少し調べてみると良いでしょう。
次回も、教師あり学習の分類を続けて取り扱っていきます。
著者プロフィール
下山輝昌
大手電機メーカーにて、ハードウェアの研究開発に従事した後、独立。独立後はソフトウェア、データ分析等において実務経験を積むとともに、数社を共同創業。その中でも合同会社アイキュベータでは、人工知能・IoTなどの可能性や方向性を研究している。最近では、オープンデータに着目し、オープンデータ活用のためのwebサービスの立ち上げ、オープンデータ×IoTによる価値創出を1つのテーマに取り組んでいる。