金貨が本物かどうか見極める

  • 22
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

CodeIQ の問題を解く

一年以上前の問題ですが CodeIQ に掲載された機械学習の問題をひとつ解いてみます。

「機械学習基礎」簡単な問題を解いて理解しよう!前篇
http://next.rikunabi.com/tech/docs/ct_s03600.jsp?p=002315

これの第一問にチャレンジです。

線形分離問題

問題

週末に海賊船で催されたPRML読書会に参加したN君は、船内に山のように積まれた金銀財宝に目を奪われました。 近くにあった宝箱の1つを開けてみると、きらきらと輝くコインが何枚も入っていました。
手に取ってみるとどれもずっしりと重みがあります。金貨に違いありません。
好きなだけ持って帰ってよいと言われ、勉強会帰りに何枚か鞄に詰め込んで帰ることにしました。
家に帰ってから少し冷静になったN君は「気前よく配っていたけれど、この金貨は本物なのだろうか」と疑い始めました。
鞄には20枚の金貨が入っていましたが、友人のアルキメデスに計測してもらったところ、20枚とも体積も重さも異なりました。
ネットで検索してみたところ、金貨の体積と重さと真贋のデータを得られました。
このデータを参考に、貰ってきた金貨の真贋を見分けてください。

元記事にある通り、綺麗に線形分離できそうなデータです。

いつも通り scikit-learn を使って解きます。

データの読み込み

import numpy as np
from sklearn.svm import LinearSVC
import matplotlib.pyplot as plt

auth = np.genfromtxt('CodeIQ_auth.txt', delimiter=' ')

# 教師データ
train_X = np.array([[x[0], x[1]] for x in auth])
# 教師データのラベル
labels = [int(x[2]) for x in auth]

# テストデータ
test_X = np.genfromtxt('CodeIQ_mycoins.txt', delimiter=' ')

データ可視化

まずはデータをプロッティングしてみます。

fig = plt.figure()
ax1 = fig.add_subplot(2,1,1)
ax2 = fig.add_subplot(2,1,2)

# 教師データから正解を抽出
correct = np.array([[x[0], x[1]] for x in auth if x[2] == 1]).T
# 同じくニセモノを抽出
wrong   = np.array([[x[0], x[1]] for x in auth if x[2] == 0]).T

# これらを散布図にプロッティングする
ax1.scatter(correct[0], correct[1], color='g')
ax1.scatter(wrong[0],   wrong[1],   color='r')
ax2.scatter(train_X.T[0], train_X.T[1], color='b')
ax2.scatter(test_X.T[0],  test_X.T[1],  color='r')

plt.legend(loc='best')
plt.show()
plt.savefig("image.png")

image.png

上図の緑が正解、赤がニセモノの金貨です。元記事のプロット通りですね。

下図は真贋データ (青) に対する、手に入れた金貨 (赤) の分布となります。

解法

線形分離問題なので LinearSVC を使います。

clf = LinearSVC(C=1)

# 訓練
clf.fit(train_X, labels)

# 分類
results = clf.predict(test_X)
for result, feature in zip(results, test_X):
    print(result, feature)

結果

1 [  0.988  17.734]
0 [ 0.769  6.842]
0 [ 0.491  4.334]
1 [  0.937  16.785]
1 [  0.844  13.435]
0 [ 0.834  9.518]
1 [  0.931  16.62 ]
1 [ 0.397  6.705]
1 [  0.917  16.544]
0 [ 0.45   3.852]
0 [ 0.421  4.612]
1 [ 0.518  9.838]
1 [  0.874  14.113]
0 [ 0.566  6.529]
0 [ 0.769  8.132]
1 [  1.043  16.066]
0 [ 0.748  9.021]
0 [ 0.61   6.828]
0 [  1.079  12.097]
1 [  0.771  13.505]

左側の 0 1 が解答になります。というわけで、例と同じ解答を得られるに至りました。