(1).やったこと
【8-5】決定木
(4).情報利得:分岐条件の有益さを測る
次に考えるべきことは、どの説明変数を分岐に用いたら、不純度をより小さくできる
のかということ。
そこで抑えるべき概念は「情報利得(information gain)である。
情報利得とは、ある変数を使ってデータ分割するとき、そのデータの分割前後でど
れだけエントロピーが減少したかを表す指標である。
先ほどと同様、cap_color_cとgill_color_bの2つの変数を使い、どちらの変数が分
岐条件として有益なのかを情報利得を用いて示す。
まず、cap_colorがcであるか否かの2つのグループに分岐し、それぞれにおける毒
キノコ割合を計算し、エントロピーを計算してみる。
※詳細はテキスト参照(ここではコード割愛)
分割する前の全体のエントロピーは0.999。
ここで分割する前のデータセットを親データセット、分割したデータを子のデー
タセットと呼ぶとした場合、情報利得は以下のように定義できる。
親のデータセットエントロピー - Σ(子データセットのサイズ/親データセット
サイズ) × 子のデータセットのエントロピー
この値が大きければ大きいほど、分割前後でエントロピーの低下が大きいため、よ
り有益な分岐条件であるとわかる。
実際に、先のエントロピーの計算を、これに当てはめてみる。
※詳細はテキスト参照(ここではコード割愛)
すると、データ分割後の平均エントロピーは0.998で、情報利得じゃ0.001となり
あまりエントロピーが減少していないことがわかる。
つまり、cap_colorがcであるか否かはあまり有益な分岐条件ではなさそうだ、
ということがわかる。
一方、gill_colorがbであるかどうかの情報利得を計算すると、以下の通り
0.269となる。上記の分岐条件よりも、エントロピーを大きく減らせるので、より
有益な分岐条件とわかる。
※詳細はテキスト参照(ここではコード割愛)
ただ、gill_colorがbである場合のエントロピーの計算については留意して起きた
いことがある。
エントロピーの定義は、厳密には空ではないカテゴリについて計算するという条件
がある。gill_colorがbである場合、frg変数が0となるサンプルがないので、エント
ロピー計算のΣに*np.log2(p1)を含めていない。
以上が決定木の生成プロセスである。
情報利得が一番大きい分岐条件でデータを分割し、さらに分割先でも同様に情報
利得を最大とする分岐条件を探索してくれるのが決定木の動作のイメージである。
※要するに、これまでの話は決定木が内部で何をやってるかの説明。
重回帰における最小二乗法のように、決定木では情報利得が最大のものを探す
ことをやっているよ、ということ。
不純度はエントロピーをここでは紹介したが、他にもジニ不純度や分類誤差など
があり。(ジニ不純度はジニ係数と関わりあり)
決定木は、分岐数でモデルの複雑さが決まる。
多くの分岐を許容するほど、複雑なモデルになることを覚えておこう。
(5).決定木のモデル構築
sklearn.treeモジュールのDecisionTreeClassfierクラスを使うことで、決定木モデ
ルを構築できる。
下記ではパラメータのcriteroinに'entropy'を指定することで、分岐条件の指標とし
てエンとロピーを設定している。
※詳細はテキスト参照(ここではコード割愛)
結果はテストデータで89%ほどの正解率。
決定木の分岐数決定のパラメータにmax_depthがあり、上記では5にしている。
深ければ当然、条件分岐数の上限も増える。
正解率を高めるためにより複雑なモデルにしたい場合は深い木を作れば良い。
(ただし、あまり深い木を作ると、過学習の危険が増すので注意)
また、決定木では、モデルを構築する際にほかのモデルでは必須になる標準化
処理をしなくても結果は変わらない。
なお、参考ではあるが、以下のように決定木のえっかを可視化することができる。
(このプログラムを実行するにはpydotplusとgraphvizのパッケージをインストール
しておく必要があるが、環境の設定が難しため、割愛)
※詳細はテキスト参照(ここではコード割愛)
【8-6】.k-MN(k近傍法)
例えば、あるグループAとBがあって、その人たちの属性がわかっているとする。
そして、そこに新しいどちらのグループに属するかわからない新しい人が来た時
に、その人と属性が近いk人を選び、そのk人の中にAの人とBの人どちらが多いのか
で、多い方のグループに新しい人を属させる、というのがk-MNによる分類方法で
ある。
k-MNはkの決定に利用する人数に相当する。
k-MNはlazy learningやmemory-based learningともいわれ、訓練データをそのまま
覚えておき、推論時に予測結果が計算される。(実質的な学習が推論時まで持ち越さ
れるため、遅延学習とも呼ばれる)
※詳細なイメージはテキストの図を参照。(ここでは割愛)
決定に使われるkの数で、結果が変わる(k=5なら3/5で有利だったのが、kを2倍に
したら4/10で不利だった、ということも起こりうるから)ので、その点は注意。
マーケティングの世界では、Look-Alikeモデルとも言われ、属性が似ている人たち
を集めて判断して、それぞれの属性に会ったアプローチを仕掛けていく際に活用され
る。
k-MNは回帰にも分類にも使える。
(1).k-MNのモデル構築
sklearn-neighboorsモジュールのKneighborsClassifierクラスを使う。
データ例としては、乳がんに関するデータセットを使う。
乳がんに関するデータセットは、load_brest_cancer関数で取得できる。
(sklearnのライブラリの中に学習用にデータが用意されている)
※詳細はテキスト参照(ここではコード割愛)
この構築したモデルでは、kを1から20にまで変化させ、訓練データとテストデータ
の正解率の変化を見ている。
kが小さい時は正解率の乖離があるが、6~8あたりで訓練とテストの正解率が近く
なる。
それ以上増やしてもモデル制度に大きな変化は見られない。
制度に改善が見られない場合、あまりkを大きくする必要はないので、本ケースに
おいては、6~8程度に設定しておくのが良さそうだとわかる。
また、これは分類タスクにおけるモデル構築の例だが、回帰の場合は
KNeighborsRegressorクラスを使う。
【8-7】サポートベクターマシン
カテゴリを識別する境界線を、マージンが最大になるように引く手法である。
例えばある分布図において、2つのグループを分ける境界線を引くとして、それぞれの
中で最も境界線(サポートベクター)との距離(マージン)が最大化するように線を引くの
がサポートベクターマシンである。
厳密には、元データを高次元空間へ変換した後、境界線を学習するのだが、本書では
詳細は割愛する。
※仕組みとしては、次元をまたぐような計算の末に線を学習するってこと。
(1).サポートベクターマシンのモデル構築
sklearn.svmモジュールのLinearSVCクラスを使う。
k-MNのモデル構築で使ったのと同じ乳がんに関するデータセットを使う。
※詳細はテキスト参照(ここではコード割愛)
サポートベクターマシンでは、標準化するとスコアが改善されることがある。
※詳細はテキスト参照(ここではコード割愛)
あとは、後にそれぞれの手法についてのモデル構築の流れと、機械学習モデル
の評価の考え方についての理解を深めると良い。(今回は割愛)
【9】機械学習の基礎(教師なし学習)
目的変数がない学習モデルのこと。
本書では、クラスタリング、主成分分析、マーケットバスケット分析について学ぶ。
【9-1】教師なし学習
(1).教師なしモデルの種類
・クラスタリング
多数のデータをいくつかの類似のグループに分類する手法。
マーケティングのアプローチで、顧客の分類や対象の絞り込みなどに使う。
・主成分分析
変数が多い場合に使う次元圧縮の手法。
もともとのデータが持つ情報をなるべく減らさずに、変数の数を減らしたい
場合に使う。
・マーケットバスケット分析(アソシエーションルール)
スーパーマーケットやコンビニ、Webサイトでの買い物の分析によく使われて
商品を買うときの組み合わせで、どれが多いかなどを分析する。
(2).この章で使うライブラリのインポート
8章と同じ。
【9-2】クラスタリング
クラスタリングは、目的変数と説明変数の関係性を表現しようとするモデル構築では
なく、データそのものに着目し、そこに隠れた構造やインサイトを見つけ出すための
モデル構築と位置付けられる。
そのため、クラスタリングは分析者自身が取り扱うデータの特徴を把握するためのm
探索的分析の第一歩として採用されることがある。
#予測というか、探索?
(1).k-means法
クラスタリングの目的は、与えられたデータを類似性の高いグループに分けること。
例えば車体形状などを持った自動車のデータ群をクラスタリングすると、軽自動車
とトラックは車体形状が違うので、異なる特徴を持った別々のクラスターに分類され
る、といったイメージになる。
クラスタリングで最も広く使われている手法はk-means法と呼ばれるもの。
テキストの図は、ある属性データ(収入、借入)をk-means法でクラスタリングした
結果、顧客が3つのグループに分かれたところを示したもの。
人間には自明に思えるこのようなデータのグループは、k-means法では以下の手人
で実現する。
・step1:入力データをプロットする。
#プロットって何?
・step2:ランダムに3つの点をプロットする。
・step3:各ランダム点を、クラスター1、クラスター2、クラスター3の重心点と
ラベリングする。
・step4:入力データの各点について、3つの重心点の中で最も近いものを選び、
その番号を自身の所属クラスター番号とする。
・step5:すべての入力データについてクラスター番号が決まった後、それぞれの
クラスターの重心(平均)を計算する。
・step6:step5で求めた3つの重心を新しいクラスターの重心点とする。
・step7:step4から6を繰り返す。ただし、繰り返し上限数に達するか、または
重心の移動距離が十分に小さくなったら終了とする。
#一番最初の3点が近すぎたらどうなるの?
それを防ぐために繰り返してるのか?(何度も繰り返して真の平均を
探り当てる?)
Scikit-learnでk-meansを実行するには、sklearn.clusterモジュールのKMeansク
ラスを使う。
KMeansクラスの初期化パラメータ(init='random')を省略するとk-means++になる。
k-means++は、k-meansの初期重心点をなるべく広げてとるように工夫した手法で、
k-meansよりも安定的な結果が得られる。
k-meansは前述の通り、ランダムに初期に重心点を配置するので、その影響で初期
一に偏りが生じる可能性があり、その解決を試みたのがk-means++である。
ほかにも重心を平均(centroid)ではなく、中央値(medoid)とするk-medoids法が
ある。平均は実在しないデータになるが、このk-medoid法は中央値のため、重心位置
が家訓尾数値を取る可能性を防げる。また外れ値による影響が少ないこともこの方法
のメリット。
(2).k-means法でクラスタリングする。
①.訓練データの作成
訓練データはsklearn.datasetsモジュールのmake_blobs関数を使って作成する。
make_blob関数は縦軸と横軸に各々標準偏差1.0の正規分布に従う乱数を生成す
る関数で、主にクラスタリング用のサンプルデータ生成に使われます。
以下の例ではrandom_stateとして10を指定している。これは乱数を生成するた
めのシード(初期値)です。値を変えるとデータの分布状況が実行のたびに変わる。
make_blobs関数は、特に引数を与えなければ、-10から+10の範囲でランダムに
2次元座標を選びmそこを中心に乱数の組を100個生成する。
最後に、生成した乱数をMatplotlibを使ってグラフ化している。
――――
#k-means法を使うためのインポート
from sklearn.cluster import KMeans
#データ取得のためのインポート
from sklearn.datasets import make_blobs
#サンプルデータ生成
#注意:make_blobsは2つの値を返すため、一方は使用しない「 _」で受け取る。
X, _ = make_blobs(random_state=10)
#グラフを描画
#colorのオプションで色付けができる。
plt.scatter(X[:,0],X[:,1],color='black')
plt.show()
――――
②.KMeansクラスを使ったクラスタリング
k-meansモデルを使って学習し、クラスタリングした結果のそれぞれにクラスター
番号と付与するプログラムは、次のようになる。(クラスターは0から始まる整数)
まず、KMeansクラスを初期化しオブジェクトを作成する。
#なぜ初期化する?
パラメータはinit='random'、n_clusters=3と設定している。
initは初期化の方法。
このようにrandomを設定すると、k-means++ではなくk-means法となる。
n_clustersにはクラスター数を設定する。
KMeansクラスのオブジェクトを作ったらfitメソッドを実行する。
するとクラスターの重心が計算され、predictメソッドを実行することでクラスタ
ー番号が予測される。
fitとpredictを一連の処理として実行するfit_predictメソッドもあるが、基本
的に構築したモデルを保存する可能性のある場合は、fitメソッドを単独で実施す
るのが良い。
#なぜ?
――――
import os
os.environ["OMP_NUM_THREADS"] = "1"
#KMeansクラスの初期化
kmeans = KMeans(init='random',n_clusters=3)
#クラスターの重心を計算
kmeans.fit(X)
#クラスター番号を予測
y_pred = kmeans.predict(X)
――――
※エラーっぽいものが出るが、無視して大丈夫。
③.結果の確認
k-meansの学習結果をグラフ化し、確認してみる。
まず、concatでデータを結合する。
x座標、y座標、クラスター番号のデータを順に横に結合するため、axis=1と
指定する。
グラフ化はクラスター番号ごとにデータを取り出し、色を指定して図示してい
る。
――――
#concatでデータを横に結合(axis=1を指定)
merge_data = pd.concat([pd.DataFrame(X[:,0]), pd.DataFrame(X[:,1]), pd.DataFrame(y_pred)], axis=1)
#上記のデータにて、x軸をfeature1、y軸をfeature2、クラスター番号をclusterと列名指定
merge_data.columns = ['feature1','feature2','cluster']
#クラスタリング結果のグラフ化
ax = None
colors = ['blue', 'red', 'green']
for i,data in merge_data.groupby('cluster'):
ax = data.plot.scatter(x='feature1',y='feature2',color=colors[i],label=f'cluster{i}', ax=ax)
plt.show()
――――
k-mean法によって、3つのグループにデータが期待した通りの分けられているのが
出力された図からわかる。
(3).金融マーケティングデータをクラスタリングする。
クラスタリング結果の活用イメージを深めるため、金融マーケティングデータを使
ってクラスタリングを実行し、結果を詳しく見る。
①.分析要求(の確認)
データはある金融機関のデータ。
顧客が定期預金口座開設の申し込みをしたか否かの変数を含んでいる。
その他の変数は、キャンペーンの実施状況、顧客の属性情報などが含まれている。
このデータをクライアントから受け取り、「そもそも私たちにどのような顧客が
いるのかわからないので分析してほしい」という分析要求を提示されたと仮定する。
教師あり学習のアプローチならば、敵預金開設したか否かを目的変数にして、モ
デルを構築したいところだが、クライアントの要求は目的変数を設置したものでは
ない。
データ分析の現場では、目的変数が定まらないことは珍しくなく、分析者自身が
データ理解を深めるための第一歩として、教師なし学習(クラスタリング)を採用す
ることがある。
②.分析対象データのダウンロードと読み込み
下記コードのURLで配布されている学習用のデータを使う。
まずは、データの取得
――――――――
#WEBからデータを取得したり、zipファイルを扱うためのライブラリをインポート
import requests, zipfile
import io
#データがあるurlの指定
zip_file_url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/00222/bank.zip'
#データを取得して展開する
r = requests.get(zip_file_url, stream=True)
z = zipfile.ZipFile(io.BytesIO(r.content))
z.extractall()
――――――――
そして、確認をする。
――――――――
#対象データを読み込み
bank= pd.read_csv('bank-full.csv', sep=';')
#先頭の5行の表示
bank.head()
――――――――
各カラムの意味は、テキスト参照。
③.データの整理と標準化
データのレコード数や数、欠損データを確認する。
※詳細なコードはここでは割愛
確認すると、45,211行、17列で、欠損データはないことがわかる。
今回は話を簡単にすすめるため、分析対象の変数をage、balance、campain、
previousに限定する。
これらの変数は、それぞれ単位が異なるので、標準化を前処理として行う。
こうすることで、値の大きな変数にクラスタリングの学習が引っ張られずに済む。
#単位をそろえるために、なるべく標準化はする?
――――――――
from sklearn.preprocessing import StandardScaler
#データの列の絞り込み
bank_sub = bank[['age','balance','campaign','previous']]
#標準化
sc = StandardScaler()
sc.fit(bank_sub)
bank_sub_std = sc.transform(bank_sub)
bank_sub.info()
――――――――
#まず、絞り込んだデータを入れた変数を作る。(bank_sub)
次に、各列の平均、各列の標準偏差を入れる変数を作る。(sc)
そして計算計算
次に、標準化したデータの変数を作る。
と、こんな感じの流れ。
④.クラスタリング処理
k-meansでクラスタリング処理を行う。
ここではクラスター数を6とする。
クラスタリング処理を終えたら、kmeansオブジェクトのlabels_属性から、各デ
ータの所属クラスター番号を配列で取得できる。
また、以下のプログラムではpandasのSeriesオブジェクトに変換してクラスタ
―別のデータ件数を集計し、クラスター攻勢を棒グラフで表示している。
――――――――
#KMeanのインポート
from sklearn.cluster import KMeans
#KMeans = KMeansクラスの初期化
kmeans = KMeans(init='random',n_clusters=6,random_state=0)
#クラスターの重心を計算
kmeans.fit(bank_sub_std)
#クラスター番号をpandasのSeriesオブジェクトに変換
labels = pd.Series(kmeans.labels_, name='cluster_number')
#クラスター番頭と件数を表示
print(labels.value_counts(sort=False))
#グラフを描画
ax = labels.value_counts(sort=False).plot(kind='bar')
ax.set_xlabel('cluster number')
ax.set_ylabel('count')
plt.show()
――――――――
結果を見ると、クラスター0やクラスター4にいるグループが比較的多いという
ことがわかる。
(4).エルボー法によるクラスター数の推定
今回はクラスター数を6と決め打ちしたが、クラスター数を事前に見積もる方法
の1つとしてエルボー法がある。
エルボー法はクラスターの重心とクラスター所属の各点の距離の総和に着目す
る。
クラスター数が1つから適切な数まで増える過程では、各点がより近いクラスター
重心に所属できるようになるので、この総和は相応に減少することが期待できる。
一方、いったん適切な数を超えて、さらにクラスター数が増える過程では、この
総和の減少度合いが低下すると予想される、
このように、クラスター数の増加に伴う重心点と各点の距離の総和の減少度合い
の変わり目に着目して、適切なクラスター数を決めようと判断しようとするのがエ
ルボー法です。
#なんか、最小二乗法に近い考え方な気がする。
要は、各データと重心の距離の総和の減少に着目するわけだ。
(これ以上ないくらい小さいところ、というわけではないからそこが最小二乗法
とは違うところだけれども)
で、クラスター数によって減少が緩やかになったところを適切なクラスター数
とする、という感じかな?
(2)の①のmake_blobs関数で生成したデータXに対してエルボー法を試す。
距離の総和は、KMeanオブジェクトのinertia_属性で取得できる。
※詳細なコードはここでは割愛
結果を見ると、クラスター数が3を超えると、縦軸の減少幅が急速に低下する。
なので、適切なクラスター数は3であると推定できる。
このように、距離の総和を見ると、理想的なクラスター数を境に、縦軸低下の
傾きが変化する。この形状がエルボー(肘)のように見えるから、エルボー法と名
付けられた。
仕組みがわかったところで、金融機関のマーケティングデータに対してもエル
ボー法を試してみる。
ここでは、クラスター数1から20までの距離の総和をグラフにしてみた。
――――――――
#エルボー法による推定。クラスター数を1から20に増やして、それぞれの距離の総和を求める。
dist_list =[]
for i in range(1,20):
kmeans= KMeans(n_clusters=i, init='random', random_state=0)
kmeans.fit(bank_sub_std)
dist_list.append(kmeans.inertia_)
#グラフを表示
plt.plot(range(1,20),dist_list,marker='+')
plt.xlabel('Numbee of clusters')
plt.ylabel('Distortion')
plt.show()
――――――――
やってみると、クラスター数が5~6付近で減少幅がやや低下しているのがわかる。
もし、エルボー法で傾向がみられない場合は、シルエット係数の算出など、その他
のクラスター数判断のための方法を試す、分析領域の固有値式に基づき分析対象変数
を変更し、再度エルボー法にかける、またはデータの概要把握と割り切り解釈可能な
範囲のクラスター数で処理を進めるなどをしよう。
#シルエット係数については後で調べること。
(2).気づいたこと・学んだこと・疑問
・クラスタリングの初期化は「初期設定」の意味
最初の重心を決めてる。
初期化というとついリセットの意味でとるが、ここでは違うので注意。
(3).簡単な復習
・クラス・インスタンスについて
クラスは設計図、インスタンスが昨日の具体的構造、fitで構造が具現化し、インス
タンスに保存される。
魔法に例えるなら、クラスが魔法の術式、インスタンスが魔法陣、fitによって魔法
が発動し、魔法陣に出現し保存される。
・ローレンツ曲線
横軸は、人の累積比、縦軸は富などの累積比で表す曲線。
y=xの直線は完全平等線と呼ばれ、富などが平等にいきわたっていることを示す。
曲線が曲がっているほど、一部の人間に縦軸ので表されているもの(富など)が偏って
いるということになる。
関連する概念としてジニ係数がある。
・ジニ係数。
完全平等線とローレンツ曲線の間の面積が完全平等線とy=0の直線の面積
の何割かで出される数値で、高いほど不平等であることがわかる。
(要するに、同じ値xにおける完全平等線とローレンツ曲線上の点の差は、それだけ
そこに配置された人が持ってないということで、不平等な量を表している)
・標準化とは
データの平均と各データの差を標準偏差で割ることで、各データが平均からどれくら
い離れているのかを表すことができる。
つまり、データがデータにおいてどの位置づけになるのかを表すことができる。
(数値によって上位or下位何%なのか、すでに決まっている)
つまり、スケールが異なるデータ間でも、そのデータの位置づけを比較することがで
きるようになる。