実装関連事項

各種プログラミング言語の基本的な書き方やソフトウェア等の使用方法について.

ナイーブベイズ (naive Bayes) は最もナイーブな機械学習法のひとつ.各アトリビュートが互いに独立に生じるというナイーブな条件下において,ベイズの定理に従って確率を掛け合わせることで最終的な分類を出力する手法.Scikit-learn にはガウシアンナイーブベイズ,多項ナイーブベイズ,ベルヌーイナイーブベイズが用意されている.ここでは,多項ナイーブベイズを用いる.

学習させるデータの構造

以下のようなデータセットを考える.このデータセットでは,60次元 (アトリビュート) のインプットベクトルに対して0または1のスカラーの値が対応している.インプットベクトルの各アトリビュートはコンマ (,) によって分割されており,インプットベクトルとターゲットベクトル (スカラー) はタブ (\t) によって分割されている.

0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0	0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1	1
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0	0
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0	1
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0	1
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1	1
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0	1
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0	1
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0	0
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0	0
.
.
.

データセット

このような構造のインスタンスが400個含まれるデータをラーニングデータセット (classification_01_learning.txt),411個含まれるデータをテストデータセット (classification_01_test.txt) とする.以下からダウンロードできる.

classification_01_learning.txt

classification_01_test.txt

学習による予測器の生成

このラーニングデータセットを学習して予測器を作るには以下のようにする.これは,Scikit-learnによるロジスティック回帰の学習方法とほぼ同じように書くことができる.ロジスティック回帰における,LogisticRegression() の代わりに MultinomialNB() を用いれば良い.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sklearn
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import confusion_matrix
import numpy as np
np.random.seed(0)

def main():
	# 1. reading data
	xtrain,ttrain=[],[]
	fin=open("classification_01_learning.txt","r")
	for i,line in enumerate(fin):
		line=line.rstrip()
		if line:
			tmp=line.split("\t")
			tmpx=tmp[0].split(",")
			tmpx=[float(j) for j in tmpx]
			tmpt=int(tmp[1])
			xtrain.append(tmpx)
			ttrain.append(tmpt)
	fin.close()
	xtrain=np.asarray(xtrain,dtype=np.float32)
	ttrain=np.asarray(ttrain,dtype=np.int32)
	
	# 2. learning
	predictor=MultinomialNB()
	predictor.fit(xtrain,ttrain)
	sklearn.externals.joblib.dump(predictor,"predictor_mnb.pkl",compress=True)
	
	# 3. evaluating the performance of the predictor
	liprediction=predictor.predict(xtrain)
	table=confusion_matrix(ttrain,liprediction)
	tn,fp,fn,tp=table[0][0],table[0][1],table[1][0],table[1][1]
	print("TPR\t{0:.3f}".format(tp/(tp+fn)))
	print("SPC\t{0:.3f}".format(tn/(tn+fp)))
	print("PPV\t{0:.3f}".format(tp/(tp+fp)))
	print("ACC\t{0:.3f}".format((tp+tn)/(tp+fp+fn+tn)))
	print("MCC\t{0:.3f}".format((tp*tn-fp*fn)/((tp+fp)*(tp+fn)*(tn+fp)*(tn+fn))**(1/2)))
	print("F1\t{0:.3f}".format((2*tp)/(2*tp+fp+fn)))
	
	# 4. printing parameters of the predictor
	print(sorted(predictor.get_params(True).items()))
	
if __name__ == '__main__':
	main()

以上のプログラムにおいて学習は以下の5ステップからなる.

  1. データの読み込み.
  2. 学習.
  3. 構築した予測器のラーニングデータセットにおける性能の評価結果の出力.
  4. 予測器のパラメーターの出力.

ナイーブベイズは最適化すべきハイパーパラメーターが基本的にはない.多項ナイーブベイズでは学習では出てこなかった情報に対して起こるゼロ頻度問題を解決するためのスムージングに対するパラメーターを最適化することができるにはできる.が,さほど効かないので,ここではしない.28行目は構築した予測器を保存するための書き方.

	# 2. learning
	predictor=MultinomialNB()
	predictor.fit(xtrain,ttrain)
	sklearn.externals.joblib.dump(predictor,"predictor_mnb.pkl",compress=True)

以上のプログラムを実行した結果は以下のようになる.この場合,正確度は0.868,MCC は0.740,F1スコアは0.875である.その下には予測器のパラメーターが出力される.

TPR     0.925
SPC     0.810
PPV     0.830
ACC     0.868
MCC     0.740
F1      0.875
[('alpha', 1.0), ('class_prior', None), ('fit_prior', True)]

構築した予測器を用いたテスト

以上で学習した予測器を読み込んで,学習データとは完全に独立なデータセット上で構築した予測器のテストを行うには以下のように書く.構築した標準化器は,26行目のように書くことで読み込むことができる.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sklearn
from sklearn.metrics import confusion_matrix
import numpy as np
np.random.seed(0)

def main():
	# 1. reading data
	xtest,ttest=[],[]
	fin=open("classification_01_test.txt","r")
	for i,line in enumerate(fin):
		line=line.rstrip()
		if line:
			tmp=line.split("\t")
			tmpx=tmp[0].split(",")
			tmpx=[float(j) for j in tmpx]
			tmpt=int(tmp[1])
			xtest.append(tmpx)
			ttest.append(tmpt)
	fin.close()
	xtest=np.asarray(xtest,dtype=np.float32)
	ttest=np.asarray(ttest,dtype=np.int32)
	
	# 2. reading predictor
	predictor=sklearn.externals.joblib.load("predictor_mnb.pkl")
	
	# 3. evaluating the performance of the predictor on the test dataset
	liprediction=predictor.predict(xtest)
	table=confusion_matrix(ttest,liprediction)
	tn,fp,fn,tp=table[0][0],table[0][1],table[1][0],table[1][1]
	print("TPR\t{0:.3f}".format(tp/(tp+fn)))
	print("SPC\t{0:.3f}".format(tn/(tn+fp)))
	print("PPV\t{0:.3f}".format(tp/(tp+fp)))
	print("ACC\t{0:.3f}".format((tp+tn)/(tp+fp+fn+tn)))
	print("MCC\t{0:.3f}".format((tp*tn-fp*fn)/((tp+fp)*(tp+fn)*(tn+fp)*(tn+fn))**(1/2)))
	print("F1\t{0:.3f}".format((2*tp)/(2*tp+fp+fn)))

if __name__ == '__main__':
	main()

これを実行した結果は以下のようになる.まずまずの性能が出ている.この場合,多分,過学習は起こっていない.

TPR     0.886
SPC     0.825
PPV     0.842
ACC     0.856
MCC     0.713
F1      0.864

学習パラメーター一覧

多項ナイーブベイズでコントロールできるハイパーパラメーターには以下のものがある.

パラメーター詳細
alpha小数を指定.ラプラススムージングのパラメーター.
fit_priorTrue または False で指定.デフォルトは True.クラスの事前確率を計算するかどうか.False を指定した場合,一様確率が設定される.
class_prior小数からなるタプルを指定.各クラスの事前確率を指定.
Hatena Google+