二値分類を最小二乗回帰により分類することができる。
  以下では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 件のコメント:
コメントを投稿