scikit-learnで決定木分析(CART)を試す
とにかく試して見るシリーズ第一弾。
なぜやるのか
いつまでもデータマート拵えおじさんのままではマズいため、比較的難易度が低くビジネスで幅広く応用が効くらしい決定木分析をやってみる
決定木分析とは
概要
決定木分析 (Decision Tree Analysis) は、機械学習の手法の一つ。木を逆にしたようなデータ構造を用いて分類と回帰を行う。
決定木分析の特徴
- 樹木状の構造で学習結果を視覚化でき、ルールをシンプルに表現できるため、論理的な解釈が容易
- データの標準化 (正規化) やダミー変数の作成を必要としないため、前処理の手間がほとんど不要
- カテゴリカルデータと数値データの両方を扱うことが可能
- 検定を行って、作成したモデルの正しさを評価することが可能
参考にしたサイト*1
ビジネスでの活用例
- 顧客別の購買履歴から自社の製品を購入している顧客の特徴を分析
- 金融機関の取引履歴から顧客属性別の貸し倒れリスクを分析
- 機械の動作ログから故障につながる指標を分析
参考にしたサイト*2
取り組んだ課題
Rの標準データセット[HairEyeColor]のデータを使ってHair[髪の色]、Eye Color[瞳の色]から、Sex[性別]を予測する決定木のモデルをPythonで作成する*3
試行過程と結果
1.データセットを確認する
# 編集前のcsvファイルを読み込んで、DataFrame化 import pandas as pd import_df = pd.read_csv('HairEyeColor.csv') import_df.head()
Unnamed: 0 | Hair | Eye | Sex | Freq | |
---|---|---|---|---|---|
0 | 1 | Black | Brown | Male | 32 |
1 | 2 | Brown | Brown | Male | 53 |
2 | 3 | Red | Brown | Male | 10 |
3 | 4 | Blond | Brown | Male | 3 |
4 | 5 | Black | Blue | Male | 11 |
決定木分析をするにあたり、このデータセットでは2工程の下処理が必要
- 各レコードをFreqの数だけ生成する
- String型の各項目をint型に置換する
2.CSVデータを加工する
参考にしたサイト*4
in_file = open("HairEyeColor.csv","r") out_file = open("HairEyeColor_Edited.csv","w") # アウトプットファイルにヘッダーを書き込み out_file.write("Hair,Eye,Sex\n") # インプットファイルのヘッダーを読み飛ばす in_file.readline() # インプットファイルの全レコードを読み込み lines = in_file.readlines() # for文で1行ずつ処理 for line in lines: # 改行コードはブランクに置換 line = line.replace("\n","") # カンマ区切りでリストに変換する line = line.split(",") # 変換処理した値を、更にカンマ区切りへ変換 row = "{},{},{}\n".format(line[1],line[2],line[3]) # 書き出し用のファイルに"Freq"の数だけ出力 freq = int(line[4]) for i in range(0,freq): out_file.write(row) in_file.close() out_file.close()
# 編集後のcsvファイルを読み込んで、DataFrame化 import_df = pd.read_csv('HairEyeColor_Edited.csv') import_df.head()
Hair | Eye | Sex | |
---|---|---|---|
0 | Black | Brown | Male |
1 | Black | Brown | Male |
2 | Black | Brown | Male |
3 | Black | Brown | Male |
4 | Black | Brown | Male |
# 加工前との整合性を確認する check = import_df.groupby(['Hair','Eye','Sex']).size() check
Hair Eye Sex
Black Blue Female 9
Male 11
Brown Female 36
Male 32
Green Female 2
Male 3
Hazel Female 5
Male 10
Blond Blue Female 64
Male 30
Brown Female 4
Male 3
Green Female 8
Male 8
Hazel Female 5
Male 5
Brown Blue Female 34
Male 50
Brown Female 66
Male 53
Green Female 14
Male 15
Hazel Female 29
Male 25
Red Blue Female 7
Male 10
Brown Female 16
Male 10
Green Female 7
Male 7
Hazel Female 7
Male 7
dtype: int64
# データの特徴を見てみる
import_df.describe()
Hair | Eye | Sex | |
---|---|---|---|
count | 592 | 592 | 592 |
unique | 4 | 4 | 2 |
top | Brown | Brown | Female |
freq | 286 | 220 | 313 |
# String型の各項目をint型に置換するための辞書を作って変換 dict = {'Hair':{'Black' :1,'Blond':2,'Brown':3,'Red' :4}, 'Eye' :{'Blue' :1,'Brown':2,'Green':3,'Hazel':4}, 'Sex' :{'Female':1,'Male' :2}} import_df['Hair'] = import_df["Hair"].map(dict['Hair']) import_df['Eye'] = import_df["Eye"].map(dict['Eye']) import_df['Sex'] = import_df["Sex"].map(dict['Sex']) import_df.head()
Hair | Eye | Sex | |
---|---|---|---|
0 | 1 | 2 | 2 |
1 | 1 | 2 | 2 |
2 | 1 | 2 | 2 |
3 | 1 | 2 | 2 |
4 | 1 | 2 | 2 |
3.決定木の分類器を作成して可視化する
参考にしたサイト*5
from sklearn import tree # 説明変数は'Hair','Eye' variables = ['Hair','Eye'] # 決定木の分類器を作成 classifier = tree.DecisionTreeClassifier() # 目的変数は'Sex' # サンプルデータで学習 classifier = classifier.fit(import_df[variables],import_df['Sex'])
# 作成した決定木を可視化する import pydotplus from sklearn.externals.six import StringIO dot_data = StringIO() tree.export_graphviz(classifier, out_file=dot_data, filled=True,rounded=True) graph = pydotplus.graph_from_dot_data(dot_data.getvalue()) from IPython.display import Image Image(graph.create_png())
4.交差検証
今回は決定木の深さだけを変えて交差検証してみる
# 交差検証1(max_depth指定なし) import numpy as np from sklearn import cross_validation as cv data = import_df.reindex(np.random.permutation(import_df.index)) variables = ['Hair','Eye'] classifier = tree.DecisionTreeClassifier() scores = cv.cross_val_score(classifier, data[variables], data['Sex'], cv=5) print(scores.mean(), scores)
0.517007950507 [ 0.48739496 0.57142857 0.47058824 0.49152542 0.56410256]
# 交差検証2(max_depth=3) data = import_df.reindex(np.random.permutation(import_df.index)) variables = ['Hair','Eye'] classifier = tree.DecisionTreeClassifier(max_depth=3) scores = cv.cross_val_score(classifier, data[variables], data['Sex'], cv=5) print(scores.mean(), scores)
0.545807753784 [ 0.46218487 0.52941176 0.56302521 0.59322034 0.58119658]
# 交差検証3(max_depth=4) data = import_df.reindex(np.random.permutation(import_df.index)) variables = ['Hair','Eye'] classifier = tree.DecisionTreeClassifier(max_depth=4) scores = cv.cross_val_score(classifier, data[variables], data['Sex'], cv=5) print(scores.mean(), scores)
0.526948093449 [ 0.58823529 0.47058824 0.55462185 0.50847458 0.51282051]
感想
- インプットしたHair, EyeのColorに対して、Sexをアウトプットする仕組みを作れないと意味がない
- パラメータ設定によるチューニングができるほどの理解には及んでいないため、もう少し理解を深めたい
- Grid Searchなるものを実行できるようになれば、パラメータを最適化できるらしい(理解度浅くても使えるということか)
- レコメンドに応用するとして、説明変数と目的変数の粒度をどうするのかが重要そうだ(ファッションのように品目がかなり細かい商品を扱うならカテゴリで、ラインナップがファッションなどに比べて限定的な金融商品などなら商品そのものでも分類できそう)
- 顧客の属性情報を説明変数に様々な切り口で分析をかければ、マーケティング対象をより詳細に理解して施策を練るのに役立てられそう
参考にしたサイト
*1:こちらのサイトを参考にしました
scikit-learn で決定木分析 (CART 法) – Python でデータサイエンス
*2:こちらのサイトを参考にしましたanalytics-news.jp
*4:こちらのサイトを参考にしましたmemopy.hatenadiary.jp
*5:こちらのサイトを参考にしました
todoa2c.github.io