"BOKU"のITな日常

還暦越えの文系システムエンジニアの”BOKU”は新しいことが大好きです。

アヤメ(iris)データでデータ分析と特徴選択の感触をつかむ/Neural Network Console応用編

2019年最初のブログです。

今回は「特徴選択(feature selection)」について、ちょっと勉強したことをまとめて、Neural Network Consoleで試してみようと思います。

f:id:arakan_no_boku:20190326212937j:plain

 

 

特徴選択(feature selection)に興味あり

さて。

今の自分の興味の中心は「特徴選択(feature selection)」です。

ディープラーニングを含む「機械学習」を行う時は、いきなり学習・評価をするのではなく以下のような手順が必要です。

  • データの分析
  • データの前処理
  • モデリング
  • 学習・評価(試行錯誤)
  • 本学習

実際のところ「データ」を分析して適切なモデルを選択したり、学習精度があがるような形にデータを加工する手順は、非常に重要です。

でも。

ふと自分のやっていることを見てみると。

そのへん、ちゃんとやれてないのが実態です。

趣味でやっているのもあって、「誰かが用意してくれたデータ」を見つけてきて、いきなり学習・評価みたいなつまみ食い的なやり方をするほうが多いですからね。

それは、ちょっと片手落ちだな。

今更ながらに気づいたわけです。

なおかつ。

そのデータの分析・前処理のうちでも特に重要だなと思ったのが、特徴集合のうち意味のある部分集合だけを選択して学習モデルを強固にする「特徴選択(feature selection)」みたいだけど、その辺が特に弱い。

じゃあ・・やらなきゃ!!・・というわけです。

 

アヤメ(iris)のデータを使ってジャブ程度にやってみる

 

そうは言っても、いきなり難しいことをしてもしょうがありません。

まずは、シンプルなデータを使って簡単なところから、練習に手をつけます。

 

「アヤメ(iris)」データをPandaのDataFrameに読み込む

 

使うのは、超有名な「アヤメ(iris)」データです。

まあ。

この辺のデータは正直データの前処理はほぼ済んだ状態で提供されてるはずですから、これを分析・加工してどうこうできるもんではないのを確認するだけになるかもしれませんが・・やってみます。

sklearn.datasetsから取得して、まずはざっと内容を見ます。

sklearnからpandasのDataFrameに変換して取得するソースです。

そのDataFrameで上から10行だけ表示してみます。 

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris

class MyDataFrame():
    def get_iris(self):
        iris = load_iris()
        return pd.DataFrame(data= np.c_[iris['data'], iris['target']],columns=iris['feature_names'] + ['target'])

mdf = MyDataFrame()
mpd = mdf.get_iris()
print(mpd.head(10))

f:id:arakan_no_boku:20181228001457j:plain

  • sepal length :萼片(がくへん)の長さ
  • sepal width: 萼片(がくへん)の幅
  • petal length:花びらの長さ
  • petal width:花びらの幅

の4つの特徴変数を使って、target 0,1,2 の3分類を識別するデータです。

それぞれが、アヤメ属に含まれる種類の名前に対応しています。

0 :setosa(ヒオウギアヤメ

1 :versicolor

2 :virginica

 

基本情報(件数・平均・標準偏差など)の確認

 

さて、まずはデータの基本情報として、件数・平均・標準偏差・分散等を確認します。

pandasのDataFrameにしてるので、この辺は簡単に取得できます。

mpd.describe()

こうすれば、下記表の情報が全部取得できます。

 

  sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)
件数 150 150 150 150
平均 5.843333 3.054 3.758667 1.198667
分散 0.681122 0.186751 3.092425 0.578532
標準偏差 0.825301 0.432147 1.758529 0.760613
最小値 4.3 2 1 0.1
四分位(25%) 5.1 2.8 1.6 0.3
中央値(50%) 5.8 3 4.35 1.3
四分位(75%) 6.4 3.3 5.1 1.8
最大値 7.9 4.4 6.9 2.5

上記の形で出力されるわけではないですが・・。

いちおう、タイトルを日本語に変更してわかりやすくしたり、分散(var)と標準偏差(std)の値だけは、以下の出力と置き換えたりしてますけれども、そのへんはご容赦ください。

mpd.var(ddof=False)
mpd.std(ddof=False)

見る限り、数字自体に特に変わった部分はありません。

petal length (cm)のバラつき(分散)が大きい(約3.09)くらいです。

正直、これで何か判断をする・・ってのも難しいです。

 

分布の状況をヒストグラムで視覚化

 

今度は、分布の感じを視覚化してみます。

下記のグラフを表示するソースは、最後にまとめてのせます。

 

まずは、王道のヒストグラムから。

f:id:arakan_no_boku:20181228012523j:plain

うーん。

データの各値の分布具合はわかりやすくなりました。

でも、これだけ見て、目的変数(0,1,2に分類)するのに意味のある部分と、そうでない部分の判断はつきませんね。

 

2つの特徴変数の組合せの散布図で重なり具合を見る

 

やりたいことは分類ですから。

分類しやすい特徴変数はどの項目の組合せなのか?を確認したいです。 

2つの特徴変数の組合せで散布図を描いて、目的変数(0,1,2)毎に色を変えた散布図を使ってやってみます。

f:id:arakan_no_boku:20181228181659j:plain

それぞれ以下の組合せのグラフです。

  • sepal length (cm) とsepal width (cm) :上段左のグラフ
  • sepal length (cm) とpetal length (cm) :上段右のグラフ
  • sepal length (cm) とpetal width (cm) :下段左のグラフ
  • petal length (cm) とpetal width (cm) :下段右のグラフ

 こうやって見ると、上段左の「sepal length (cm) とsepal width (cm)」の組合せ以外は、非常にきれいに分布してます。

なので。

そのままでもそこそこ精度はでるが、「sepal width (cm)」を特徴変数から外すした方がより精度がでるんじゃないか?

そんな仮説は立てられそうです。

 

仮説に基づいてやってみる

 

仮説をたてたら、試してみます。

簡単にやるなら・・Neural Network Console・・ということで。

 

まずは、データセットを作ります。

 

データ分析用にpandasのDataFrameにしたので、それをCSVに出力します。

CSV出力しただけだと、左端に連番が出力されていたり、ヘダーの名称が「sepal length (cm)」とかになっているので、EXCELで開き、余分な列である左端の列(連番)を消して、ヘダーの名称を「x__1」のようにNeural Network Consoleのルールに沿って修正する必要があります。

arakan-pgm-ai.hatenablog.com

あとは、全体で150件のデータを適当に割り振って、トレーニング用とテスト用のCSVにわけて、それぞれ「iris_train.csv」「iris_test.csv」とでも名前をつけておきます。

trainが0.7:testが0.3くらいの比率に普通はするのですが、今回は条件を厳しくするために、0.5:0.5で75件ずつにバッサリわけてみました。

この辺のCSVデータの加工は手作業です。

データも小さいし、難しい加工でもないので・・。

さて。

 

ネットワークモデル

 

学習用のネットワークモデルはこんな感じ。

f:id:arakan_no_boku:20181229164130j:plain

inputは以下のようなCSVです。

f:id:arakan_no_boku:20181229164827j:plain

xの列が4つなので「4」です。

f:id:arakan_no_boku:20190104155241j:plain

 

4つの特徴変数の列をすべて使うパターン

 

ちょっと、パラメータを変更すると結果が変わるのです。

が、一番良かった結果は、Max Epochは100、バッチサイズは5くらいでやった時のAccuracy97.29%です。

f:id:arakan_no_boku:20181229224142j:plain

特徴変数を3つに減らしたパターン

 

これを受けて、今度は「sepal width (cm)」を外したデータでやってみます。

この1列削除する作業も手作業でやりました。

f:id:arakan_no_boku:20181229224456j:plain

仮説としては。

こちらの方が元データでゴチャゴチャとクロスしている部分が少なくなっているので、より精度があがるように思えます。

でも、実際にやってみると・・結果はほぼ同じです。

f:id:arakan_no_boku:20181229224812j:plain

まあ。

やっぱりそうだよなあ・・という感じですね。

今回は、とりあえずのとっかかりなので・・、こんなもんですかね?

 

グラフを書いた部分のpythonソース

 

最後にpythonソースコードを書いておきます。 

ヒストグラムの表示の部分です。 

import matplotlib.pyplot as plt

# mpdにpandasのDataFrameでirisのデータがある前提です
x = mpd['sepal length (cm)']
plt.subplot(221)
plt.hist(x,bins=6)
plt.xlabel('sepal length (cm)')
plt.subplot(222)
x1 = mpd['sepal width (cm)']
plt.hist(x1,bins=6)
plt.xlabel('sepal width (cm)')
plt.subplot(223)
x2 = mpd['petal length (cm)']
plt.hist(x2,bins=6)
plt.xlabel('petal length (cm)')
plt.subplot(224)
x3 = mpd['petal width (cm)']
plt.hist(x3,bins=6)
plt.xlabel('petal width (cm)')
plt.show()

次に散布図の表示の部分です 

plt.subplot(221)
x = mpd['sepal length (cm)']
y = mpd['sepal width (cm)']
t = mpd['target']
plt.scatter(x,y,c=t)
plt.xlabel('sepal length (cm)')
plt.ylabel('sepal width (cm)')

plt.subplot(222)
x1 = mpd['sepal length (cm)']
y1 = mpd['petal length (cm)']
t1 = mpd['target']
plt.scatter(x1,y1,c=t1)
plt.xlabel('sepal length (cm)')
plt.ylabel('petal length (cm)')

plt.subplot(223)
x2 = mpd['sepal length (cm)']
y2 = mpd['petal width (cm)']
t2 = mpd['target']
plt.scatter(x2,y2,c=t2)
plt.xlabel('sepal length (cm)')
plt.ylabel('petal width (cm)')

plt.subplot(224)
x3 = mpd['petal length (cm)']
y3 = mpd['petal width (cm)']
t3 = mpd['target']
plt.scatter(x3,y3,c=t3)
plt.xlabel('petal length (cm)')
plt.ylabel('petal width (cm)')
plt.show()

ではでは。