kb84tkhrのブログ

何を書こうか考え中です あ、あと組織とは関係ないってやつです 個人的なやつ

PPP3: 機械学習 Matplotlib scikit-learn

Jupyter上にMatplotlibでグラフを描画するにはまずおまじない

%matplotlib inline

%matplotlib notebookとすると対話的にグラフを表示するらしいけど
どう操作するのかわからなかった
まあいいや

それで

import matplotlib.pyplot as plt
x = [1,2,3,4]
y = [10,12,15,20]
plt.plot(x, y)
plt.show()

出たでた

ヒストグラム

from numpy.random import normal

x = normal(size=200)
plt.hist(x, bins=40)

これだけでも出る
ラベルとかを追加

plt.xlabel('x')
plt.ylabel('y (Bin Count)')
plt.title('Histogram Example')
plt.axis([-4,4,0,25])
plt.grid(True)

これは同じセルに入れないといけない
いまだにどう動いてるのかモデルが見えない

plt.show()

これでグラフが表示されるそうなんだけどなくても表示されてた

次は散布図

x = np.arange(20)
y = 2*x + 1

えーとこれは

y
---
array([ 1,  3,  5,  7,  9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33,
       35, 37, 39])

そういうことね
[2*xk + 1 for xk in x]みたいに理解すればいいのかな

線形回帰
polyってついてるから線形だけじゃないんだろうけど
deg=1で1次式で近似するよう指定してるってことかな

m, b = np.polyfit(x, y, deg=1)

結果

m, b

(2.0000000000000004, 1.0000000000000009)

グラフを表示

plt.scatter(x, y) 
plt.plot(x, m*x+b, 'r-')
plt.show()

scatter()が散布図で、plotはなんていうんだろうとにかく折れ線を書くものかな

ここまでは単に数値計算のライブラリだよね
かろうじてpolyfitだけ予測っぽいけど

いよいよ機械学習っぽいところへ

サンプル用のデータがある
これはありがたいね

from sklearn import datasets
diabetes = datasets.load_diabetes()

どれどれ

diabetes

{'data': array([[ 0.03807591,  0.05068012,  0.06169621, ..., -0.00259226,
          0.01990842, -0.01764613],
        ...,
 'target': array([151.,  75., 141., 206., 135.,  97., 138.,  63., 110., 310., 101.,
        ...,
 'DESCR': '.. _diabetes_dataset:\n\n ...',
 'feature_names': ['age', ...,
 'data_filename': '/home/takahiro/study/PPP3-mac/mlprj/venv/lib/python3.6/site-packages/sklearn/datasets/data/diabetes_data.csv.gz',
 'target_filename': '/home/takahiro/study/PPP3-mac/mlprj/venv/lib/python3.6/site-packages/sklearn/datasets/data/diabetes_target.csv.gz'} ...

入った

DataFrameに入れる

df = pd.DataFrame(diabetes.data, columns=("age", "sex", "bmi", "map", "tc", "ldl", "hdl", "tch", "ltg", "glu"))
df['target'] = diabetes.target
df.head()

targetってなんなん

1年後の疾患進行状況を数値で表したデータ

これか
これを予測するからターゲットになるってことだなたぶん

bmi列とtarget列にどのような関係があるかを線形回帰モデルを利用して学習させます。


ここでも線形回帰か
ディープラーニングとかじゃないんですか!(偏見

まずはbmiだけ取り出す

diabetes_X = diabetes.data[:, np.newaxis, 2]
diabetes_X

array([[ 0.06169621],
       [-0.05147406],
       [ 0.04445121],
       [-0.01159501],
       ...

取り出せたみたいだけどdiabetes.data[:, np.newaxis, 2]って何やってんの
リストのスライスと、
np.newaxisってなんだ 新しい軸?
2っていうのは(0から数え始めて)2番目のデータを持ってこいってことかな
そもそも添字部分にカンマ区切りで何書いてるんだ
そんなのpythonにあったっけ・・・
普通のlistじゃなくてNumpy特有の書き方なのかな

type(diabetes.data)

numpy.ndarray

なるほどNumPyのクラスらしい
printarray(...)って表示されるやつはみんなこれ?

順番に見ていくか
diabetes.data[:] から

diabetes.data[:]

array([[ 0.03807591,  0.05068012,  0.06169621, ..., -0.00259226,
         0.01990842, -0.01764613],
       ...,
       [-0.04547248, -0.04464164, -0.0730303 , ..., -0.03949338,
        -0.00421986,  0.00306441]])

diabetes.dataと同じだな
これは予想通り

newaxisを追加

diabetes.data[:, np.newaxis]

array([[[ 0.03807591,  0.05068012,  0.06169621, ..., -0.00259226,
          0.01990842, -0.01764613]],

       ...,

       [[-0.04547248, -0.04464164, -0.0730303 , ..., -0.03949338,
         -0.00421986,  0.00306441]]])

えーと?
ひとつ入れ子が深くなった?
1次元増えたということになるのか・・・?

diabetes.data[:, np.newaxis].shape

(442, 1, 10)

ということになってるみたい
だから何?

さらに2を追加すると2番目の項目が取り出されるっぽい

diabetes.data[:, np.newaxis, 2]

array([[ 0.06169621],
       ...,
       [-0.0730303 ]])

どうもピンとこない気がする
2って書いたら2番目を取り出してるってことはわかるけど
np.newaxisって書くと入れ子が深くなって
2って書くと2番目を取り出すっていうのはどういうことなん

そもそもdiabetes.data[:, 2]じゃダメなの

diabetes.data[:, 2]

array([ 0.06169621, -0.05147406,  0.04445121, -0.01159501, -0.03638469,
        ...,
        0.03906215, -0.0730303 ])

なるほどそうなるからか
ちょっとピンと来た
次元が減らないようにとりあえず次元を足しておくってことか

array([[ 0.06169621], ..., [-0.0730303 ]])より
array([ 0.06169621, ..., -0.0730303 ])の方が自然な気もするけどね!
他の関数とのやりとりするには上の形のほうが都合いいってことだろうな

公式見よ
ここだな

Indexing — NumPy v1.17 Manual

まずなによりこれ

Unlike lists and tuples, numpy arrays support multidimensional indexing for multidimensional arrays.

普通のリストやタプルと違って、x[1,3]という形で書ける
これがとまどいのかなりの部分を占めた

Note that if one indexes a multidimensional array with fewer indices than dimensions, one gets a subdimensional array.

3次元のarrayで2次元だけ指定すれば1次元のarrayが返される

The slicing and striding works exactly the same way it does for lists and tuples except that they can be applied to multiple dimensions as well.

スライスやストライドはリストやタプルで使うのと同じように使える

Note that slices of arrays do not copy the internal array data but only produce new views of the original data.

arrayのスライスはコピーを作るのではなくて元のデータの見方を変えるだけ
そうなんだ
ということは[:]っていうのは「そのままなにもしない」っていうことになるんだな

the np.newaxis object can be used within array indices to add new dimensions with a size of 1

np.newaxisを使うとサイズ1で次元を追加できる

これくらいでいいだろう
話を元にもどす
与えられたデータとターゲットをを学習用とテスト用に分ける

diabetes_X_train =diabetes_X[:-20]
diabetes_X_test =diabetes_X[-20:]
diabetes_y_train =diabetes.target[:-20]
diabetes_y_test =diabetes.target[-20:]

いよいよ予測

from sklearn import linear_model

regr = linear_model.LinearRegression()
regr.fit(diabetes_X_train, diabetes_y_train)
diabetes_y_pred = regr.predict(diabetes_X_test)

できたかな

diabetes_y_pred

array([225.9732401 , 115.74763374, 163.27610621, 114.73638965,
       120.80385422, 158.21988574, 236.08568105, 121.81509832,
        99.56772822, 123.83758651, 204.73711411,  96.53399594,
       154.17490936, 130.91629517,  83.3878227 , 171.36605897,
       137.99500384, 137.99500384, 189.56845268,  84.3990668 ])

できてる
本当の値は

diabetes_y_test

array([233.,  91., 111., 152., 120.,  67., 310.,  94., 183.,  66., 173.,
        72.,  49.,  64.,  48., 178., 104., 132., 220.,  57.])

・・・ちょっとなんとも言えない
決定係数を見る

from sklearn.metrics import r2_score
print(f'r^2 score {r2_score(diabetes_y_test, diabetes_y_pred):.02f}')

r^2 score 0.47

0.47っていうのはどうなのか
低そう

グラフにする

plt.scatter(diabetes_X_test, diabetes_y_test, color='black')
plt.plot(diabetes_X_test, diabetes_y_pred, color='blue', linewidth = 3)
...

これはモデルがよくなかったってことみたい
じゃあ次のPDCA行くよ(行かない

大量のデータを扱うにはNumPyの行列計算に落とし込むとか
モリーを使い切るとか特有のテクニックがある

終わり!