Python - 機械学習③ クラスタリング

機械学習によるクラスタリングを行ってみます。

クラスタリング用のデータ準備

まずはクラスタリング用のデータを準備します。

クラスタリングでは学習データとテストデータという区別はありません。

ただデータを与えれば、データを種類ごとに分けてくれます。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# matplotlibとnumpyをインポート
import matplotlib.pyplot as plt
import numpy as np

# x軸の範囲を定義
x_max = 1
x_min = -1

# y軸の範囲を定義
y_max = 2
y_min = -1

# スケールを定義(1単位に何点を使うか)
SCALE = 50

# テストデータの割り合い(全データに対してテストデータは30%)
TEST_RATE = 0.3

# データ生成
x = np.arange(x_min, x_max, 1 / float(SCALE)).reshape(-1, 1)
# xの2乗
y = x ** 2
y_noise = y + np.random.randn(len(y), 1) * 0.5 # ノイズを乗せる

クラスタリング

クラスタリングを行います。今回はデータを3つに分けてグラフに表示します。

7行目のn_clustersに分類数を設定します。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from sklearn import cluster

# xデータとyデータを結合
data = np.c_[x, y_noise]

# 3つのクラスタに分割
model = cluster.KMeans(n_clusters=3)
model.fit(data)

# 分割結果
# 0から2の番号がつけられている
labels = model.labels_

### データの表示
plt.scatter(x[labels == 0], y_noise[labels == 0], c='blue', s=30, marker='^', label='cluster 0')
plt.scatter(x[labels == 1], y_noise[labels == 1], c='black', s=30, marker='x', label='cluster 1')
plt.scatter(x[labels == 2], y_noise[labels == 2], c='red', s=30, marker='*', label='cluster 2')

# 元の線を点線スタイルで表示
plt.plot(x, y, linestyle='-', label='non noise curve')

# x軸とy軸の範囲を設定
plt.xlim(x_min, y_max)
plt.ylim(y_min, y_max)

# 凡例の表示位置を指定
plt.legend()

# グラフを表示
plt.show()

実行結果は下記の通りです。

[実行結果]

結果

データが青の▲マーク、黒の×マーク、赤の★マークの3つに分類されていることが分かります。

Python - 機械学習② 回帰

機械学習による回帰を行ってみます。

回帰問題のデータ準備

まずは回帰問題用のデータを準備します。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# matplotlibとnumpyをインポート
import matplotlib.pyplot as plt
import numpy as np

# x軸の範囲を定義
x_max = 1
x_min = -1

# y軸の範囲を定義
y_max = 2
y_min = -1

# スケールを定義(1単位に何点を使うか)
SCALE = 50

# テストデータの割り合い(全データに対してテストデータは30%)
TEST_RATE = 0.3

# データ生成
x = np.arange(x_min, x_max, 1 / float(SCALE)).reshape(-1, 1)
# xの2乗
y = x ** 2
y_noise = y + np.random.randn(len(y), 1) * 0.5 # ノイズを乗せる

# 学習データとテストデータに分割(分類問題、回帰問題で使用)
def split_train_test(array):
length = len(array)
n = int(length * (1 - TEST_RATE))

indices = list(range(length))
np.random.shuffle(indices)
idx_train = indices[:n]
idx_test = indices[n:]

return sorted(array[idx_train]), sorted(array[idx_test])

# インデックスリストを分割
indices = np.arange(len(x)) # インデックス値のリスト
idx_train, idx_test = split_train_test(indices)

# 学習データ
x_train = x[idx_train]
y_train = y_noise[idx_train] # ノイズが乗ったデータ

# テストデータ
x_test = x[idx_test]
y_test = y_noise[idx_test] # ノイズが乗ったデータ

回帰

[コード]

1次式(直線)、2次式で回帰させてみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from sklearn import linear_model

### 1次式で回帰

X1_TRAIN = x_train
X1_TEST = x_test

# 学習
model = linear_model.LinearRegression()
model.fit(X1_TRAIN, y_train) # y_trainは学習データ()

# グラフに描画
plt.plot(x_test, model.predict(X1_TEST), linestyle='-.', label='poly deg 1')


### 2次式で回帰

X2_TRAIN = np.c_[x_train**2, x_train]
X2_TEST = np.c_[x_test**2, x_test]

# 学習
model = linear_model.LinearRegression()
model.fit(X2_TRAIN, y_train)

# グラフに描画
plt.plot(x_test, model.predict(X2_TEST), linestyle='--', label='poly deg 2')


### データの表示

plt.scatter(x_train, y_train, c='blue', s=30, marker='*', label='train')
plt.scatter(x_test, y_test, c='red', s=30, marker='x', label='tes')

# 元の線を点線スタイルで表示
plt.plot(x, y, linestyle='-', label='non noise curve')

# x軸とy軸の範囲を設定
plt.xlim(x_min, y_max)
plt.ylim(y_min, y_max)

# 凡例の表示位置を指定
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0)

# グラフを表示
plt.show()

実行結果は下記の通りです。


[実行結果]

結果

1次式は直線、2次式は元の線とかなり近い形になっていることが分かります。

Python - 機械学習① 分類

機械学習による分類を行ってみます。

まずは分類問題用のデータを準備します。

分類問題のデータ準備

データを原点から近いか遠いかで2つの種類に分け、さらに学習データとテストデータに分け、最終的に4種類のデータを準備します。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# matplotlibとnumpyをインポート
import matplotlib.pyplot as plt
import numpy as np

# x軸の範囲を定義
x_max = 1
x_min = -1

# y軸の範囲を定義
y_max = 2
y_min = -1

# スケールを定義(1単位に何点を使うか)
SCALE = 50

# テストデータの割り合い(全データに対してテストデータは30%)
TEST_RATE = 0.3

# データ生成
x = np.arange(x_min, x_max, 1 / float(SCALE)).reshape(-1, 1)
# xの2乗
y = x ** 2
y_noise = y + np.random.randn(len(y), 1) * 0.5 # ノイズを乗せる

# 学習データとテストデータに分割(分類問題、回帰問題で使用)
def split_train_test(array):
length = len(array)
n = int(length * (1 - TEST_RATE))

indices = list(range(length))
np.random.shuffle(indices)
idx_train = indices[:n]
idx_test = indices[n:]

return sorted(array[idx_train]), sorted(array[idx_test])

# インデックスリストを分割
indices = np.arange(len(x)) # インデックス値のリスト
idx_train, idx_test = split_train_test(indices)

# 学習データ
x_train = x[idx_train]
y_train = y_noise[idx_train] # ノイズが乗ったデータ

# テストデータ
x_test = x[idx_test]
y_test = y_noise[idx_test] # ノイズが乗ったデータ

# クラスの閾値。原点からの半径
CLASS_RADIUS = 0.6

labels = (x ** 2 + y_noise ** 2) < CLASS_RADIUS ** 2

# 学習データとテストデータに分割
label_train = labels[idx_train] # 学習データ
label_test = labels[idx_test] # テストデータ

## グラフ描画

# 近いか遠いかで2種類に分け、さらに学習データとテストデータに分ける。全部で3種類。

# 学習データ(近い)散布図
plt.scatter(x_train[label_train], y_train[label_train], c='black', s=30, marker='*', label='near train')
# テストデータ(遠い)散布図
plt.scatter(x_train[label_train != True], y_train[label_train != True], c='black', s=30, marker='+', label='far train')

# テストデータ(近い)散布図
plt.scatter(x_test[label_test], y_test[label_test], c='red', s=30, marker='^', label='near test')
# テストデータ(遠い)散布図
plt.scatter(x_test[label_test != True], y_test[label_test != True], c='blue', s=30, marker='x', label='far test')

# 元の線を点線スタイルで表示
plt.plot(x, y, linestyle=':', label='non noise curve')

# クラスの分離円
circle = plt.Circle((0, 0), CLASS_RADIUS, alpha=0.1, label='near area')
ax = plt.gca()
ax.add_patch(circle)

# x軸とy軸の範囲を設定
plt.xlim(x_min, y_max)
plt.ylim(y_min, y_max)

# 凡例の表示位置を指定
plt.legend(bbox_to_anchor=(1.05, 1), loc='uppder left', borderaxespad=0)

# グラフを表示
plt.show()

[実行結果]

結果

近いエリア(near are)の中に、黒い★マーク(near train)と赤い▲マーク(near test)が含まれ、黒い+マーク(far train)と青い×マーク(far test)が含まれていないことが分かります。

これで分類問題用の4種類のデータを準備することができました。

分類

上記で準備したデータを使って分類処理を行っていきます。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 分類問題を解くためにSVMとういうアルゴリズムをインポート
from sklearn import svm
from sklearn.metrics import confusion_matrix, accuracy_score

# [x, y]の組み合わせからなる学習データとテストデータの配列を作成
data_train = np.c_[x_train, y_train]
data_test = np.c_[x_test, y_test]

# SVMの分類器を作成、学習
classifier = svm.SVC(gamma=1)
classifier.fit(data_train, label_train.reshape(-1))

# テストデータで評価(予測)
pred_test = classifier.predict(data_test)

# Accuracyを表示
print('accuracy_score:\n', accuracy_score(label_test.reshape(-1), pred_test))
print()

# 混合行列を表示
print('Confusion matrix:\n', confusion_matrix(label_test.reshape(-1), pred_test))

[実行結果]
accuracy_score:
 0.8666666666666667

Confusion matrix:
[[15 4]
[ 0 11]]


accuracyは正答率を意味し、テストデータ全体における正解の割り合いを表します。

86.6%であればまあまあの分類性能ということになるでしょうか。

Python - 機械学習の前準備

機械学習の代表的な処理として次の3つを挙げることができます。

  • 分類
    与えられたデータから分類(クラス)を予測します。
  • 回帰
    与えられたデータから数値を予測します。
  • クラスタリング
    データの性質に従って、データの塊(クラスタ)を作成します。

今回は機械学習の前準備としまして、データの準備グラフ化を行っていきます。

データの準備・グラフ化

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# matplotlibとnumpyをインポート
import matplotlib.pyplot as plt
import numpy as np

# x軸の範囲を定義
x_max = 1
x_min = -1

# y軸の範囲を定義
y_max = 2
y_min = -1

# スケールを定義(1単位に何点を使うか)
SCALE = 50

# テストデータの割り合い(全データに対してテストデータは30%)
TEST_RATE = 0.3

# データ生成
x = np.arange(x_min, x_max, 1 / float(SCALE)).reshape(-1, 1)
# xの2乗
y = x ** 2
y_noise = y + np.random.randn(len(y), 1) * 0.5 # ノイズを乗せる

# 学習データとテストデータに分割(分類問題、回帰問題で使用)
def split_train_test(array):
length = len(array)
n = int(length * (1 - TEST_RATE))

indices = list(range(length))
np.random.shuffle(indices)
idx_train = indices[:n]
idx_test = indices[n:]

return sorted(array[idx_train]), sorted(array[idx_test])

# インデックスリストを分割
indices = np.arange(len(x)) # インデックス値のリスト
idx_train, idx_test = split_train_test(indices)

# 学習データ
x_train = x[idx_train]
y_train = y_noise[idx_train]

# テストデータ
x_test = x[idx_test]
y_test = y_noise[idx_test]

### グラフ描画

# 分析対象点の散布図
plt.scatter(x, y_noise, label='target')

# 元の線を点線スタイルで表示
plt.plot(x, y, linestyle=':', label='non noise curve')

# x軸 y軸の範囲を設定
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)

# 凡例の表示位置を指定
plt.legend(bbox_to_anchor=(1.05, 1), loc='uppder left', borderaxespad=0)

# グラフを表示
plt.show()

[実行結果]

結果

青い●が機械学習で使用するデータとなります。

点線はノイズが乗る前の元の曲線を表しています。

Python matplotlib - グラフの描画

Pythonでグラフを描画する場合に、matplotlibというライブラリがよく使われます。

折れ線グラフや散布図などを描くことができ、詳細に表示設定をすることもできます。

グラフの描画

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 方程式を設定するためにNumpyをインポート
import numpy as np
# グラフを描画するためにmatplotlibをインポート
import matplotlib.pyplot as plt

# x軸の領域と精度を設定
x1 = np.arange(-3, 3, 0.1)
# 方程式のy値を設定
y1 = np.sin(x1)

# x値とy値ともにランダムな値を設定
x2 = np.random.rand(100) * 6 -3
y2 = np.random.rand(100) * 6 -3

# figureオブジェクトを作成
plt.figure()

# 1つのグラフで表示する設定
plt.subplot(1, 1, 1)

# 線形とマーカー、ラベルを設定しグラフを描画する
plt.plot(x1, y1, marker='o', markersize=5, label='line')

# 散布図を描画する
plt.scatter(x2, y2, label='scatter')

# 凡例表示を設定
plt.legend()

# グリッド線を表示
plt.grid(True)

# グラフ表示
plt.show()

[実行結果]

結果

Python Numpy⑥ - 行列での四則演算

Numpy行列で四則演算を行っていきます。

行列の準備

まずNumpyをインポートし、2行3列の行列を2つ作成します。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

# 1つめの2次元配列を定義
x = np.array([[1, 2, 3], [4, 5, 6]])
print('行列 x')
print(x)
print()

# 2つめの2次元配列を定義
y = np.array([[1, 2, 3], [0.1, 0.5, 0.8]])
print('行列 y')
print(y)

[実行結果]

行列 x
[[1 2 3]
 [4 5 6]]

行列 y
[[1.  2.  3. ]
 [0.1 0.5 0.8]]

行列の四則演算


形状が同じ行列同士ではそのまま四則演算が適用できます。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
print('# 和')
print(x + y)
print()

print('# 差')
print(x - y)
print()

print('# 積')
print(x * y)
print()

print('# 商')
print(x / y)

[実行結果]

# 和
[[2.  4.  6. ]
 [4.1 5.5 6.8]]

# 差
[[0.  0.  0. ]
 [3.9 4.5 5.2]]

# 積
[[1.  4.  9. ]
 [0.4 2.5 4.8]]

# 商
[[ 1.   1.   1. ]
 [40.  10.   7.5]]

行列のブロードキャスト

先ほどは同じ形状同士で四則演算を行いましたが、配列のサイズが完全に一致しなくても片方の次元の長さが1または0の場合、同じ値によって自動的にサイズ拡張されてから計算されます。

[コード]

1
2
3
4
5
z = np.array([[1, 2, 3]])
print(z)
print()

print(x + z)

[実行結果]

[[1 2 3]]

[[2 4 6]
 [5 7 9]]

1行3列のデータが2行3列に拡張されて計算されていることが分かります。


最後に行列ではない単純な数字を足してみます。


[コード]

1
print(x + 100)

[実行結果]

[[101 102 103]
 [104 105 106]]

全ての要素に対して100が足されていることが分かります。

ブロードキャスト機能を使うといちいち要素ごとに四則演算を行う必要がなくシンプルにコードを書くことができ大変便利です。

Python Numpy⑤ - 行列を連結する

今回は、Numpy行列を連結してみます。

行列を連結する

まずNumpyをインポートし、2行3列の行列を2つ作成します。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

# 1つめの2次元配列を定義
x = np.array([[1, 2, 3], [4, 5, 6]])
print('行列 x')
print(x)
print()

# 2つめの2次元配列を定義
y = np.ones((2, 3))
print('行列 y')
print(y)

[実行結果]

行列 x
[[1 2 3]
 [4 5 6]]

行列 y
[[1. 1. 1.]
 [1. 1. 1.]]

numpy.r_[]を使うと、行について連結することができます。

[コード]

1
2
z = np.r_[x, y]
print(z)

[実行結果]

[[1. 2. 3.]
 [4. 5. 6.]
 [1. 1. 1.]
 [1. 1. 1.]]

numpy.c_[]を使うと、列について連結することができます。

[コード]

1
2
z = np.c_[x, y]
print(z)

[実行結果]

[[1. 2. 3. 1. 1. 1.]
 [4. 5. 6. 1. 1. 1.]]

Python Numpy④ - 転置をとる/行列の形状を変える

Numpy行列の転置をとる方法と形状を変える方法を試してみます。

転置をとる

まずNumpyをインポートし、2行3列の行列を作成します。

1
2
3
4
import numpy as np

# 2次元配列を定義
x = np.array([[1, 2, 3], [4, 5, 6]])

転置をとるにはシンプルに .T とするだけです。

[コード]

1
2
3
4
5
6
print('転置前')
print(x)
print()

print('転置後')
print(x.T)

[実行結果]

転置前
[[1 2 3]
 [4 5 6]]

転置後
[[1 4]
 [2 5]
 [3 6]]

3次元配列を転置することも可能です。

[コード]

1
2
3
4
5
6
7
8
9
# 3次元配列を定義
x = np.array([[[1, 2], [3, 4], [5, 6]]])

print('転置前')
print(x)
print()

print('転置後')
print(x.T)

[実行結果]

転置前
[[[1 2]
  [3 4]
  [5 6]]]

転置後
[[[1]
  [3]
  [5]]

 [[2]
  [4]
  [6]]]

データだけをみるとよく分かりませんが、形状を確認すると逆順になっていることが分かります。

[コード]

1
2
3
4
5
6
print('転置前')
print(x.shape)
print()

print('転置後')
print(x.T.shape)

[実行結果]

転置前
(1, 3, 2)

転置後
(2, 3, 1)

形状を変える

配列の形状を変えるには reshapeメソッド を使います。

[コード]

1
2
3
4
5
6
# 2行3列の配列を定義
x = np.array([[1, 2, 3], [4, 5, 6]])

# 1行6列の配列に変更します。
y = x.reshape(1, 6)
print(y)

[実行結果]

[[1 2 3 4 5 6]]

配列を変換する場合、要素数が一致しないとエラーになりますので気を付けてください。

Python Numpy③ - 行列の要素へのアクセス

Numpy行列の要素へのアクセスを試してみます。

行列の要素へのアクセス

まずNumpyをインポートし、2行3列の行列を作成します。

1
2
3
import numpy as np

x = np.array([[1, 2, 3], [4, 5, 6]])

2行3列目の要素を取得するには次のように指定します。

1
print(x[1, 2])

添え字は0から始まるため2行目は 1、3列目は 2 と指定します。

[実行結果]

6

1行目の行をそのまま取得します。
1
print(x[0])

[実行結果]

[1 2 3]

2次元配列のまま1列目だけを取得します。

1
print(x[:, 0:1])

[実行結果]

[[1]
 [4]]

1次元配列で1列目を取得します。

1
print(x[:, 0])

[実行結果]

[1 4]

Python Numpy② - リストから行列を作成

リスト型データからNumpyの行列を作成します。

リストデータから配列を作成する

まず、以下のようにNumpyをインポートしておきます。

1
import numpy as np

1次元配列を作成します。

Numpyでは (3, ) という配列の形で表現されます。

1
2
x = np.array([1, 2, 3])
print(x)

[実行結果]

[1 2 3]

次に2行3列の2次元データを作成します。

元となるデータは、リスト型データの中にリスト型データがあるイメージです。

Numpyでは (2, 3) という配列の形で表現されます。

1
2
3
x = np.array([[1, 2, 3], [4, 5, 6]])
print(x)

[実行結果]

[[1 2 3]
 [4 5 6]]

配列の形とデータ型を取得する

配列の形は shape という属性で取得することができます。

1
print(x.shape)

[実行結果]

(2, 3)

データ型は dtype という属性で取得することができます。
1
print(x.dtype)

[実行結果]

int32