二値分類を最小二乗回帰により分類することができる。
以下では0~9の文字を一対他法により分類している。
1 2 3 4 5 6 7 8 9 10 | %matplotlib inline import numpy as np import matplotlib.pyplot as plt import pandas as pd from pandas import Series, DataFrame from sklearn import cross_validation from numpy.random import normal from sklearn.utils import shuffle from sklearn.metrics import f1_score import itertools |
訓練データの読み込み
0~9の文字はそれぞれ500個ずつある。
1 2 3 4 5 6 7 8 9 10 | #一行一行が一文字 train = DataFrame() for i in range(10): train = pd.concat([train, pd.read_csv("/Users/Hirono/data_science/Data/digit_csv/digit_train%i.csv"% i, header =None)]) train_target = [] for i in range(10): for j in itertools.repeat(i, 500): train_target.append(j) train_data, train_target = shuffle(train, train_target) train_data = train_data.reset_index().drop("index", axis = 1) #indexのコラムをおとす |
テストデータの読み込み
0~9の文字はそれぞれ200個ずつある。
データはふつうはMNistとかからとってくればok(前章参照)
1 2 3 4 5 6 7 8 9 | test = DataFrame() for i in range(10): test = pd.concat([test, pd.read_csv("/Users/Hirono/data_science/Data/digit_csv/digit_test%i.csv"% i, header =None)]) test_target = [] for i in range(10): for j in itertools.repeat(i, 200): test_target.append(j) test_data, test_target = shuffle(test, test_target) test_data = test_data.reset_index().drop("index", axis = 1) | |
1 2 3 4 | #パラメータ h = 0.2 #カーネル関数のパラメータ N = 1000 #traindataを使う数 u = 0.1 #正則化パラメータ |
|
いつものように訓練データからカーネルマトリックスをもとめる
1 2 3 4 5 6 7 8 9 10 11 12 13 | #カーネル関数 def K(x,y): return np.exp(- np.dot((x-y),(x-y)) / (2 * h ** 2)) kernel_matrix = DataFrame() series = [] for i in range(N): series = [] for x in train_data[:N].iterrows(): series.append(K(x[1], train_data.ix[i])) series = Series(series) kernel_matrix = pd.concat([kernel_matrix, series], axis = 1) kernel_matrix.columns = range(N) |
下は、たとえばs = 3としたときに、testdataが3かそうでない数字かを返してくれる関数
3だったら1, 3でなければ-1がかえってくる。
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 | def one_versus_the_other(s, test_data): def posi_or_nega(x): if x == s: x = 1 return x else: x = -1 return x t = Series(train_target[:N]) t = t.apply(lambda x: posi_or_nega(x) ) tmp = np.linalg.inv(np.dot(kernel_matrix,kernel_matrix) + u * np.eye(N) ) ws = np.dot(np.dot(tmp, kernel_matrix), t) #もとめたいθ def sign(x): #0を-1にいれたいので、自分で定義 if x > 0: return 1 else: return -1 def f(x): #モデル関数 y = 0 for i, w in enumerate(ws): y += w * K(x, train_data.ix[i]) return sign(y) return f(test_data) |
2000個のtestdataを0~9の数字に分類する。
1 2 3 4 5 6 | classification = [] for j in range(2000): arr = [] for i in range(10): arr.append(one_versus_the_other(i, test_data.ix[j])) classification.append(np.argmax(arr)) |
正解率は92%だった。
1 2 3 4 | classification = Series(classification) test_target = Series(test_target) classification[classification == test_target].value_counts().sum() /2000. #=> 0.92 |
具体的な集計結果
1 2 3 4 5 | pred_and_target = pd.concat([classification, test_target], axis = 1) pred_and_target.columns = ["pred", "target"] pred_and_target = DataFrame(pred_and_target.groupby(["pred", "target"]).size()).reset_index() pred_and_target = pred_and_target.rename(columns={0: 'count'}) #0は文字列じゃなくて数字なので、rename時に注意 pred_and_target.pivot(index="pred", columns="target").fillna(0) |
表の読み方は、たとえば、0だと予想したものが実際は5であったものが19個あったという意味である。
計算時間がかなりかかってしまったので、今回は訓練データは1000個しかつかっていない。
だから、もっと訓練データを増やせば正解率をあげることができると考えられる。
(実際に、訓練データを500から1000に増やすことで正解率が0.88→0.92に向上した。) そのうち計算時間が短縮されるようにコードを改善したい。
pythonメモ
1 2 | shuffle([1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]) #=> [[2, 5, 3, 4, 1], [2, 5, 3, 4, 1], [2, 5, 3, 4, 1]] |
1 2 | itertools.repeat(10, 3) => 10, 10 ,10 |
Seriesの値それぞれに関数適用
1 | Series.apply(lambda x: posi_or_nega(x)) |
1 2 | "%s %i" % ("aaaa", 4.0) #'aaaa 4' |
1 2 | map(lambda x: x[1], [[1,2], [3,4]]) #[2, 4] |
indexという名前のコラムをおとす
1 | df.drop("index", axis = 1) |
dataframe の nanを0でうめる
1 | df.fillna(0) |
columnのkeyをvalueにrenameする
1 | df.rename(columns={0: 'count'}) |
f値をもとめる。もし二値分類ならaverage = 'binary'とする
1 | f1_score(classification, test_target, average='macro' ) |
seriesのvalueの数を数える
1 | series.value_counts() |
seriesをindex順に並び替える
1 | series.sort_index() |
最大値をとる配列のindexをかえす。最大値が二つ以上あるときは最初のindexのほうを返す。
1 2 3 4 | np.array([0, 1, 2, 3, 10, 5, 6, 7, 8, 9]).argmax() #=>4 np.array([0, 1, 2, 3, 10, 10, 6, 7, 8, 9]).argmax() #=>4 |
最後の集計の流れよくつかいそうだからもう一回
1 2 3 4 5 | pred_and_target = pd.concat([classification, test_target], axis = 1) pred_and_target.columns = ["pred", "target"] #1 pred_and_target = DataFrame(pred_and_target.groupby(["pred", "target"]).size()) #2 pred_and_target = pred_and_target.reset_index().rename(columns={0: 'count'}) #3 pred_and_target.pivot(index="pred", columns="target").fillna(0) #4 |
1
2
3
4
0 件のコメント:
コメントを投稿