草薙の研究ログ

英語の先生をやってます。

Rで混同行列から感度・特異度などの指標

例えば,何かの指標なりモデルを用いて,
二値的に何かの状態がある(陽性)かない(陰性)かを検査する方法を作るとする。
そのパフォーマンスは以下のような真の状態と検査結果の混同行列を見るとわかる。

この場合の混同行列は,

真の状態が陽性 真の状態が陰性
検査結果が陽性 真陽性 偽陽性
検査結果が陰性 偽陰性 真陰性

っていうかんじで,ここから,

  • 適中率/Accuracy(全体の内,真陽性と真陰性が占める割合)
  • エラー率/Error Rate(1-的中率)
  • 感度/Sensitivity (真の状態が陽性であるもののうち,陽性と判断できた割合)
  • 特異度/Specificity (真の状態が陰性であるもののうち,陰性と判断できた割合)
  • 陽性適中率 (陽性と判断したもののうち,真の状態が陽性である割合)
  • 陰性適中率 (陰性と判断したもののうち,真の状態が陰性である割合)
  • 陽性尤度比 (真の状態が陽性であるひとが陰性であるひとよりも何倍検査結果が陽性になるか)
  • 陰性尤度比 (真の状態が陰性であるひとが陽性であるひとよりも何倍検査結果が陰性になるか)

といった指標が与えられる。
当たり前だけど,完全によい検査ってのは実現しにくくい。
感度をあげようとすると特異度が下がるような場合がほとんど。
これらの指標のバランスを実務的状況から判断して適切に保たなければならない。

私には実務的にこれをやらなければならない案件がある。もちろんRにはこれらの指標を与えたり,さらにROC曲線を描いてくれたりするパッケージがいっぱいあるんだけど,これらを調べるよりも自分でコード書くほうが絶対楽なんで,自分で書いてみた。混同行列を与えたら以上のものを全部返す。

my.indices<-function(CM){
	Rate<-CM/sum(CM)
	TP<-CM[1,1]
	TPr<-Rate[1,1]
	FP<-CM[1,2]
	FPr<-Rate[1,2]
	FN<-CM[2,1]
	FNr<-Rate[1,1]
	TN<-CM[2,2]
	TNr<-Rate[2,2]
	Acc<-(TP+TN)/sum(CM)
	Err<-1-Acc
	Sens<-TP/(TP+FN)
	Spec<-TN/(FP+TN)
	PPV<-TP/(TP+FP)
	NPV<-TN/(FN+TN)
	LRP<-Sens/(1-Spec)
	LRN<-(1-Sens)/Spec
	
	Result<-list(
		"Confusion Matrix"=CM,
		"Confusion Rates"=Rate,
		"Accuracy"=Acc,
		"Error Rate"=Err,
		"Sensitivity"=Sens,
		"Sepcificity"=Spec,
		"PPV"=PPV,
		"NPV"=NPV,
		"LR+"=LRP,
		"LR-"=LRN
		)	
	print(Result,digits=3)
}

こんな感じ。

my.indices(matrix(c(50,8,321,650),2,2))

$`Confusion Matrix`
     [,1] [,2]
[1,]   50  321
[2,]    8  650

$`Confusion Rates`
        [,1]  [,2]
[1,] 0.04859 0.312
[2,] 0.00777 0.632

$Accuracy
[1] 0.68

$`Error Rate`
[1] 0.32

$Sensitivity
[1] 0.862

$Sepcificity
[1] 0.669

$PPV
[1] 0.135

$NPV
[1] 0.988

$`LR+`
[1] 2.61

$`LR-`
[1] 0.206

うむ。