Python機械学習
ここではSVMによる識別は交差検定について簡単にまとめます.
sklearn-learnはリファレンスも親切ですので,そちらも確認してみてください.
sklearn-learnはリファレンスも親切ですので,そちらも確認してみてください.
1.SVMに挑戦
#####################################
#SVMによる機械学習
#編集日:2016/9/5
#製作者:栁澤
#プログラムを書き換える必要は特にないです.
#####################################
from sklearn.svm import LinearSVC
import numpy as np
from sklearn.preprocessing import StandardScaler #正規化(標準得点化)するのに使う
from sklearn.metrics import accuracy_score #正解率を求めるのに使う
# 学習データ(1列目:時間、2列目:教師信号、3列目以降:使用するデータ)###################
data = np.loadtxt('data.csv', delimiter=',')#学習データの読み込み
print("学習データ")
print(data)
timedata = data[:,0] #時間データ
t_signal = data[:,1] #教師信号
data_training = data[:,2::] #学習信号
label_training = [int(x) for x in t_signal] #教師信号の形式を加工
#標準得点化
scaler = StandardScaler()
scaler.fit(data_training)
data_training = scaler.transform(data_training)
##########################################################################################
# 評価データ(1列目:時間、2列目:教師信号、3列目以降:使用するデータ)###################
data_test = np.loadtxt('testdata.csv', delimiter=',')#評価データの読み込み
print("評価データ")
print(data_test)
true_singal = data_test[:,1] ##正解の情報
data_test = data_test[:,2::] #学習信号
#標準得点化
scaler = StandardScaler()
scaler.fit(data_test)
data_test = scaler.transform(data_test)
##########################################################################################
# 学習(ソフトマージンSVM(線形))
estimator = LinearSVC(C=1)#コストパラメータCを調整すること(Cが大きいほどハードマージンSVMに近づく)
estimator.fit(data_training, label_training)#上で作った識別器に学習データの教師信号を入力する
# 予測する
label_prediction = estimator.predict(data_test)
print("識別結果")
print(label_prediction)#識別結果を表示
correct_rate = accuracy_score(true_singal, label_prediction)
print("正解率 " + str(correct_rate*100) +"%")
2.交差検定(クロスバリデーション)
上の方法は学習データと評価データを分けて作成しておく必要があったが,これらの方法を使えば自動的にデータを学習データと評価データに分けてくれる.
2.1 KFold
#単純にn_splitsの数でデータを分割する
from sklearn.model_selection import KFold
from sklearn import datasets
iris = datasets.load_iris()#アイリスのデータを読み込む(iris.dataが数値データでiris.targetが教師信号(正解))
kf = KFold(n_splits=3, random_state=None, shuffle=False)#KFoldで交差検定をするための準備
for train_index, test_index in kf.split(iris.data):
print("TRAIN:", train_index, "TEST:", test_index)
X_train, X_test = iris.data[train_index], iris.data[test_index]
y_train, y_test = iris.target[train_index], iris.target[test_index]
注意:例えば 最初の50個がクラスAのデータ,次の50個がクラスB,最後の50個がクラスCのようなデータセットをKFold でデータを3分割すると,学習データに全く含まれていないクラスが出てくるので,その場合は,StratifiedKFoldを使うこと.
2.2 StratifiedKFold
#単純にn_splitsの数でデータを分割せずに、全体のクラスの比率を反映して分割する
from sklearn.model_selection import StratifiedKFold
from sklearn import datasets
iris = datasets.load_iris() #アイリスのデータを読み込む(iris.dataが数値データでiris.targetが教師信号(正解))
skf = StratifiedKFold(n_splits=3, random_state=None, shuffle=False)#StratifiedKFoldで交差検定をするための準備
#このも方法だけは、教師信号(ラベルデータ、target)もここに入力する(おそらく、クラスの比率を変えないために、ラベルの情報が必要だから)
for train_index, test_index in skf.split(iris.data,iris.target):
print("TRAIN:", train_index, "TEST:", test_index)
X_train, X_test = iris.data[train_index], iris.data[test_index]
y_train, y_test = iris.target[train_index], iris.target[test_index]
2.3 LeaveOneOut
#テストデータは1サンプルのみ、その他全部で学習する
from sklearn.model_selection import LeaveOneOut
from sklearn import datasets
iris = datasets.load_iris()#アイリスのデータを読み込む(iris.dataが数値データでiris.targetが教師信号(正解))
loo = LeaveOneOut()
for train_index, test_index in loo.split(iris.data):
#print("TRAIN:", train_index, "TEST:", test_index)
X_train, X_test = iris.data[train_index], iris.data[test_index]
y_train, y_test = iris.target[train_index], iris.target[test_index]
3. SVMの正解率を求める(交差検定を利用)
#########################
#日付:2017年4月13日
#作成者:栁澤
#内容: 交差検定用 3種類あるよ!
#########################
from sklearn.model_selection import cross_val_score
from sklearn import svm
from sklearn.model_selection import KFold
from sklearn.model_selection import LeaveOneOut
from sklearn.model_selection import StratifiedKFold
import numpy as np
from sklearn.svm import LinearSVC
nn = 5 #交差検定するときの分割数
dataname = 'B' #ファイル名
filename = dataname + '.csv'
data = np.loadtxt(filename, delimiter=',') #データの読み込み
data = np.array(data,dtype=np.float32) #データをfloat32にする
row,col = data.shape #データの大きさを調べる
label_data = data[:,1] #教師信号
nirs_data = data[:,2:col] #計測データ
#①単純にn_splitsの数でデータを分割する
kf = KFold(n_splits=nn, random_state=None, shuffle=False)
#②テストデータは1サンプルのみ、その他全部で学習する
loo = LeaveOneOut()
#③単純にn_splitsの数でデータを分割せずに、全体のクラスの比率を反映して分割する
skf = StratifiedKFold(n_splits=nn, random_state=None, shuffle=False)
clf = LinearSVC(C=10) #線形SVM(いままで使っていたやつ)
#clf = svm.SVC(kernel='linear', C=1) #非線形も対応(これはlinerだけど)
#clf = svm.SVC(kernel='rbf', C=1, gamma=0.1) #カーネル関数fbfで非線形SVM
scores = cross_val_score(clf, nirs_data, label_data, cv=skf) #cvの交差検定でclfの識別器で正答率を求める
print(scores)#交差検定でわけたそれぞれのセットの正答率を表示
correct_rate = 100*sum(scores)/len(scores)#平均正答率を求める
print(correct_rate)#平均正答率を表示
#loo(LeaveOneOut)のときのみコメントアウト
#print(100*sum(scores)/16)#これが平均正答率になる
4.パラメータの決定方法(グリッドリサーチ)
最適なパラメータを見つけたいときは以下のように書けば,各条件での正答率と標準偏差を計算してくれる.
#########################
#日付:2017年4月13日
#作成者:栁澤
#内容: パラメータ検討用
#########################
from sklearn.model_selection import GridSearchCV
from sklearn import svm, grid_search
import numpy as np
import csv
nn = 4 #交差検定するときの分割数
dataname = 'B'
filename = dataname + '.csv'
data = np.loadtxt(filename, delimiter=',')
data = np.array(data,dtype=np.float32) #データをfloat32にする
row,col = data.shape #データの大きさを調べる
label_data = data[:,1] #教師信号
nirs_data = data[:,3:col] #計測データ
#検討するパラメータ
parameters ={'kernel':('linear', 'rbf'), 'C':[0.1, 1, 10, 100] ,'gamma':[0.001, 0.01, 0.1 ,1 ,10]}
svr = svm.SVC()#使用する識別器
clf = grid_search.GridSearchCV(svr, parameters, n_jobs = -1, cv=nn)#グリッドサーチの設定
clf.fit(nirs_data, label_data)#学習
savedata = ['params','mean_score','sd']
for params, mean_score, all_scores in clf.grid_scores_:
print ("{:.3f} (+/- {:.3f}) for {}".format(mean_score, all_scores.std() / 2, params))
savedata = np.vstack([savedata,[params,mean_score, all_scores.std() / 2]])
savefilename = 'result_' + dataname + '.csv'
with open(savefilename, 'w') as f:
writer = csv.writer(f, lineterminator='\n') # 改行コード(\n)を指定しておく
writer.writerows(savedata) # 2次元配列も書き込める
@wikiの入力上?の問題から「parameters ={'kernel':('linear', 'rbf'), 'C':[0.1, 1, 10, 100] ,'gamma':[0.001, 0.01, 0.1 ,1 ,10]}」の大括弧{}は全角になっていますので,使うときは半角に修正してね.
参考
読み込んでいるデータの形式について説明しておく.
時間 | 教師信号 | データ1 | データ2 | ・・・ | データn |
0 | 0 | x11 | x21 | ・・・ | xn1 |
1 | 0 | x12 | x22 | ・・・ | xn2 |
2 | 1 | x13 | x23 | ・・・ | xn3 |
3 | 1 | x14 | x24 | ・・・ | xn4 |
・・・ | ・・・ | ・・・ | ・・・ | ・・・ | ・・・ |
t | 0 | x1t | x2t | ・・・ | xnt |