Sklearnを使ってみる1
かなり以前になりますが、
でsklearnをインストールしたので、『実践 機械学習システム』を読みながら、sklearnをいじってみたいと思います。
で、特に理由はありませんが、スタートは第2章のIrisデータセットを扱う章から、始めます。Irisデータセット自体はsklearnをインストールしたときに一緒についてきます。
最初にがっつりとしたコードが出てくるのが以下のようなコードです。
from matplotlib import pyplot as plt
from sklearn.datasets import load_iris
import numpy as np
data = load_iris()
features=data["data"]
feature_names=data["feature_names"]
target=data["target"]
target_names=data["target_names"]
labels=target_names[target]
for t,marker,c in zip (xrange(3),">ox","rgb"):
plt.scatter(features[target == t,0],features[target == t,1],marker=marker,c=c)
本の冒頭にて、この本ではpython2.7をベースにかかれているのですが、自分はPython3.4を使っているのでうまく動きません。それに加え、そもそもコードの意味もよくわかりません。。。
とりあえず、これを動くようにしたり解読したりするところから始めたいと思います。
まず、動かす。
まず、動くようにすることを考えます。
どうやら、xrangeといところが問題だったようです。python3.xではrangeの方にxrangeが統合されているようです。
それと最後にplt.show()も追記が必要です。
結局のところ、以下のようにすれば動作します。
from matplotlib import pyplot as plt
from sklearn.datasets import load_iris
import numpy as np
data = load_iris()
features=data["data"]
feature_names=data["feature_names"]
target=data["target"]
target_names=data["target_names"]
labels=target_names[target]
for t,marker,c in zip (range(3),'>ox','rgb'):
plt.scatter(features[target == t,0],features[target == t,1],marker=marker,c=c)
plt.show()
Irisデータセットの構造
とりあえず動いたので、もっと詳細を解読していきたいと思います。
次に、何をしているのかよくわからなかったのが、上の例でいう5行目(空白行は除いて)から9行目の部分。
features=data["data"]
feature_names=data["feature_names"]
target=data["target"]
target_names=data["target_names"]
labels=target_names[target]
これはIrisデータセットがディクショナリー型になっていることがわかり理解できました。
Irisデータセットは次のようなディクショナリー型のデータになっています。
####説明のための擬似コード。
load_iris={data:(測定値などの一覧),
DESCR:(引用情報などの参考情報),
target_names:(あやめ(Iris)の種類の名前),
featurenames:(「 花弁の長さ」など特徴量の名前),
target:(あやめの種類の名前にそれぞれ割り当てる番号)
}
ディクショナリのキーを取得しようとすると次のようになります。
#最初の>>python3を実行する部分 は省略
>>from sklearn.datasets import load_iris
>>data=load_iris()
>>data.keys()
dict_keys(['DESCR', 'data', 'feature_names', 'target', 'target_names'])
#表示される順番は毎回違うようです。
#####ファイルに保存して実行する場合はこうする。
from sklearn.datasets import load_iris
data=load_iris()
print(data.keys())
###→例えばiris.pyという名前で保存し、ターミナルから実行すると同じような結果になる。
各項目の中をみてみます。まずは、'data'というキーに対応する要素は次のようになっています。
#最初の>>python3を実行する部分 は省略
>>from sklearn.datasets import load_iris
>>data=load_iris()
>>data.data()
array([[ 5.1, 3.5, 1.4, 0.2],
[ 4.9, 3. , 1.4, 0.2],
[ 4.7, 3.2, 1.3, 0.2],
[ 4.6, 3.1, 1.5, 0.2],
[ 5. , 3.6, 1.4, 0.2],
[ 5.4, 3.9, 1.7, 0.4],
[ 4.6, 3.4, 1.4, 0.3],
[ 5. , 3.4, 1.5, 0.2],
[ 4.4, 2.9, 1.4, 0.2],
[ 4.9, 3.1, 1.5, 0.1],
[ 5.4, 3.7, 1.5, 0.2],
[ 4.8, 3.4, 1.6, 0.2],
[ 4.8, 3. , 1.4, 0.1],
[ 4.3, 3. , 1.1, 0.1],
[ 5.8, 4. , 1.2, 0.2],
[ 5.7, 4.4, 1.5, 0.4],
[ 5.4, 3.9, 1.3, 0.4],
[ 5.1, 3.5, 1.4, 0.3],
[ 5.7, 3.8, 1.7, 0.3],
[ 5.1, 3.8, 1.5, 0.3],
[ 5.4, 3.4, 1.7, 0.2],
[ 5.1, 3.7, 1.5, 0.4],
[ 4.6, 3.6, 1. , 0.2],
[ 5.1, 3.3, 1.7, 0.5],
[ 4.8, 3.4, 1.9, 0.2],
[ 5. , 3. , 1.6, 0.2],
[ 5. , 3.4, 1.6, 0.4],
[ 5.2, 3.5, 1.5, 0.2],
[ 5.2, 3.4, 1.4, 0.2],
[ 4.7, 3.2, 1.6, 0.2],
[ 4.8, 3.1, 1.6, 0.2],
[ 5.4, 3.4, 1.5, 0.4],
[ 5.2, 4.1, 1.5, 0.1],
[ 5.5, 4.2, 1.4, 0.2],
[ 4.9, 3.1, 1.5, 0.1],
[ 5. , 3.2, 1.2, 0.2],
[ 5.5, 3.5, 1.3, 0.2],
[ 4.9, 3.1, 1.5, 0.1],
[ 4.4, 3. , 1.3, 0.2],
[ 5.1, 3.4, 1.5, 0.2],
[ 5. , 3.5, 1.3, 0.3],
[ 4.5, 2.3, 1.3, 0.3],
[ 4.4, 3.2, 1.3, 0.2],
[ 5. , 3.5, 1.6, 0.6],
[ 5.1, 3.8, 1.9, 0.4],
[ 4.8, 3. , 1.4, 0.3],
[ 5.1, 3.8, 1.6, 0.2],
[ 4.6, 3.2, 1.4, 0.2],
[ 5.3, 3.7, 1.5, 0.2],
[ 5. , 3.3, 1.4, 0.2],
[ 7. , 3.2, 4.7, 1.4],
[ 6.4, 3.2, 4.5, 1.5],
[ 6.9, 3.1, 4.9, 1.5],
[ 5.5, 2.3, 4. , 1.3],
[ 6.5, 2.8, 4.6, 1.5],
[ 5.7, 2.8, 4.5, 1.3],
[ 6.3, 3.3, 4.7, 1.6],
[ 4.9, 2.4, 3.3, 1. ],
[ 6.6, 2.9, 4.6, 1.3],
[ 5.2, 2.7, 3.9, 1.4],
[ 5. , 2. , 3.5, 1. ],
[ 5.9, 3. , 4.2, 1.5],
[ 6. , 2.2, 4. , 1. ],
[ 6.1, 2.9, 4.7, 1.4],
[ 5.6, 2.9, 3.6, 1.3],
[ 6.7, 3.1, 4.4, 1.4],
[ 5.6, 3. , 4.5, 1.5],
[ 5.8, 2.7, 4.1, 1. ],
[ 6.2, 2.2, 4.5, 1.5],
[ 5.6, 2.5, 3.9, 1.1],
[ 5.9, 3.2, 4.8, 1.8],
[ 6.1, 2.8, 4. , 1.3],
[ 6.3, 2.5, 4.9, 1.5],
[ 6.1, 2.8, 4.7, 1.2],
[ 6.4, 2.9, 4.3, 1.3],
[ 6.6, 3. , 4.4, 1.4],
[ 6.8, 2.8, 4.8, 1.4],
[ 6.7, 3. , 5. , 1.7],
[ 6. , 2.9, 4.5, 1.5],
[ 5.7, 2.6, 3.5, 1. ],
[ 5.5, 2.4, 3.8, 1.1],
[ 5.5, 2.4, 3.7, 1. ],
[ 5.8, 2.7, 3.9, 1.2],
[ 6. , 2.7, 5.1, 1.6],
[ 5.4, 3. , 4.5, 1.5],
[ 6. , 3.4, 4.5, 1.6],
[ 6.7, 3.1, 4.7, 1.5],
[ 6.3, 2.3, 4.4, 1.3],
[ 5.6, 3. , 4.1, 1.3],
[ 5.5, 2.5, 4. , 1.3],
[ 5.5, 2.6, 4.4, 1.2],
[ 6.1, 3. , 4.6, 1.4],
[ 5.8, 2.6, 4. , 1.2],
[ 5. , 2.3, 3.3, 1. ],
[ 5.6, 2.7, 4.2, 1.3],
[ 5.7, 3. , 4.2, 1.2],
[ 5.7, 2.9, 4.2, 1.3],
[ 6.2, 2.9, 4.3, 1.3],
[ 5.1, 2.5, 3. , 1.1],
[ 5.7, 2.8, 4.1, 1.3],
[ 6.3, 3.3, 6. , 2.5],
[ 5.8, 2.7, 5.1, 1.9],
[ 7.1, 3. , 5.9, 2.1],
[ 6.3, 2.9, 5.6, 1.8],
[ 6.5, 3. , 5.8, 2.2],
[ 7.6, 3. , 6.6, 2.1],
[ 4.9, 2.5, 4.5, 1.7],
[ 7.3, 2.9, 6.3, 1.8],
[ 6.7, 2.5, 5.8, 1.8],
[ 7.2, 3.6, 6.1, 2.5],
[ 6.5, 3.2, 5.1, 2. ],
[ 6.4, 2.7, 5.3, 1.9],
[ 6.8, 3. , 5.5, 2.1],
[ 5.7, 2.5, 5. , 2. ],
[ 5.8, 2.8, 5.1, 2.4],
[ 6.4, 3.2, 5.3, 2.3],
[ 6.5, 3. , 5.5, 1.8],
[ 7.7, 3.8, 6.7, 2.2],
[ 7.7, 2.6, 6.9, 2.3],
[ 6. , 2.2, 5. , 1.5],
[ 6.9, 3.2, 5.7, 2.3],
[ 5.6, 2.8, 4.9, 2. ],
[ 7.7, 2.8, 6.7, 2. ],
[ 6.3, 2.7, 4.9, 1.8],
[ 6.7, 3.3, 5.7, 2.1],
[ 7.2, 3.2, 6. , 1.8],
[ 6.2, 2.8, 4.8, 1.8],
[ 6.1, 3. , 4.9, 1.8],
[ 6.4, 2.8, 5.6, 2.1],
[ 7.2, 3. , 5.8, 1.6],
[ 7.4, 2.8, 6.1, 1.9],
[ 7.9, 3.8, 6.4, 2. ],
[ 6.4, 2.8, 5.6, 2.2],
[ 6.3, 2.8, 5.1, 1.5],
[ 6.1, 2.6, 5.6, 1.4],
[ 7.7, 3. , 6.1, 2.3],
[ 6.3, 3.4, 5.6, 2.4],
[ 6.4, 3.1, 5.5, 1.8],
[ 6. , 3. , 4.8, 1.8],
[ 6.9, 3.1, 5.4, 2.1],
[ 6.7, 3.1, 5.6, 2.4],
[ 6.9, 3.1, 5.1, 2.3],
[ 5.8, 2.7, 5.1, 1.9],
[ 6.8, 3.2, 5.9, 2.3],
[ 6.7, 3.3, 5.7, 2.5],
[ 6.7, 3. , 5.2, 2.3],
[ 6.3, 2.5, 5. , 1.9],
[ 6.5, 3. , 5.2, 2. ],
[ 6.2, 3.4, 5.4, 2.3],
[ 5.9, 3. , 5.1, 1.8]])
実際に各サンプルに対する測定値が格納されている様子がわかります。
次は、'target_names'に対応する要素、あやめ(Iris)の種類の名前としてどういう要素が格納されているかみます。
調べ方は上記とほとんど同じです。
#最初の>>python3を実行する部分 は省略
>>from sklearn.datasets import load_iris
>>data=load_iris()
>>data.target_names
array(['setosa', 'versicolor', 'virginica'],
dtype='
setosaとversicolorとvirginicaという名前があるのがわかります。最後についている余分なやつはよく意味はわかりませんが、とりあえずスルーします。
同様に、'feature_names'に対応する要素の中をみます。
#最初の>>python3を実行する部分 は省略
>>from sklearn.datasets import load_iris
>>data=load_iris()
>>data.feature_names
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
最後に、'target'に対応する要素の中身。
#最初の>>python3を実行する部分 は省略
>>from sklearn.datasets import load_iris
>>data=load_iris()
>>data.target
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
で最後のlabels=target_names[target]の行で、0→setosa、1→versicolor、2→virginicaに対応させる処理をしています。
これも最初あまり意味がわかりませんでしたが、numpyの文法です。
target_namesのリストから0か1か2に対応するインデックスの要素を取り出し、新しいリストを作るという意味です。
事実上ラベル付けを行っていることになります。よく使う利用法らしい。
>>from sklearn.datasets import load_iris
>>data=load_iris()
>>> features=data['data']
>>> features_name=data['feature_names']
>>> target=data['target']
>>> target_names=data['target_names']
>>> label=target_names[target]
>>> label
array(['setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'setosa',
'setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'setosa',
'setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'setosa',
'setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'setosa',
'setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'setosa',
'setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'setosa',
'setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'setosa',
'setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'setosa',
'setosa', 'setosa', 'versicolor', 'versicolor', 'versicolor',
'versicolor', 'versicolor', 'versicolor', 'versicolor',
'versicolor', 'versicolor', 'versicolor', 'versicolor',
'versicolor', 'versicolor', 'versicolor', 'versicolor',
'versicolor', 'versicolor', 'versicolor', 'versicolor',
'versicolor', 'versicolor', 'versicolor', 'versicolor',
'versicolor', 'versicolor', 'versicolor', 'versicolor',
'versicolor', 'versicolor', 'versicolor', 'versicolor',
'versicolor', 'versicolor', 'versicolor', 'versicolor',
'versicolor', 'versicolor', 'versicolor', 'versicolor',
'versicolor', 'versicolor', 'versicolor', 'versicolor',
'versicolor', 'versicolor', 'versicolor', 'versicolor',
'versicolor', 'versicolor', 'versicolor', 'virginica', 'virginica',
'virginica', 'virginica', 'virginica', 'virginica', 'virginica',
'virginica', 'virginica', 'virginica', 'virginica', 'virginica',
'virginica', 'virginica', 'virginica', 'virginica', 'virginica',
'virginica', 'virginica', 'virginica', 'virginica', 'virginica',
'virginica', 'virginica', 'virginica', 'virginica', 'virginica',
'virginica', 'virginica', 'virginica', 'virginica', 'virginica',
'virginica', 'virginica', 'virginica', 'virginica', 'virginica',
'virginica', 'virginica', 'virginica', 'virginica', 'virginica',
'virginica', 'virginica', 'virginica', 'virginica', 'virginica',
'virginica', 'virginica', 'virginica'],
)
for文のブロック
次にわからなかったのが、この行です。
for t,marker,c in zip (range(3),’>ox’,’rgb’):
まず、このzipというのはfor文を3つ同時に処理する関数のようです。(なんて便利なんだ。。。)
上の例でいえば、変数tにはrange(3)の中身を順番に代入、変数markerには{>,o,x}を順番に代入、変数cには{r,g,b}を順番に代入、ということです。
で、rgbの方はいいとして、>oxってなんなのかと。
これは、実際に描画するときのマーカーの形(?)だそうです。matplotlibのオプションです。
詳しくはここのページを(Markers--matplotlib.markers)
もう少しだ。。。次はこの行。
plt.scatter(features[target == t,0],features[target == t,1],marker=marker,c=c)
まず、scatterは散布図を描画するmatplotlib提供の関数です。
features[target==t,0]というのは、features自体が実際にデータ(数値)が格納されているリストなわけですが、その中でも[ ]の中の条件に一致するものだけを抽出していますよ、という意味です。
つまり上の例でいえば、featuresの0番目の要素の一覧の中、targetが例えば0(=0であればそれはsetosaなわけですが)に該当するもの、
さらに言い換えておけば、target=0のときはsetosaのfeaturesの0番目要素だけを抽出するという意味です。
なんか言い換えたけどわかりやすくなっている気がしない。
さらに、plt.scatter()やplt.plot()などmatplotlibの描画系は先にグラフを生成して、最後にplt.show()をすると、最後にグラフが重ねて描画されます。
今回のケースではfor文として3回処理されるので、3種類のプロットが重ねて描かれます。
上記のようなことも含め、実際に冒頭のコードを実行すると、次のような画面が出てきます。
そうすると、本に書かれている6枚のグラフのうち、一番左上のグラフが描画されます。