こんにちは。
整形外科医師ブロガーのボククボです。
今回もMATLABについてのプチ情報です。
MATLAB分類学習器アプリを使えば、
ワンクリックで、20種類以上のアルゴリズムで
機械学習をして、分類器を作成してくれます。
perfcurveという関数もあり、
もうワンクリックすると、ROC曲線も描いてくれます。
とても便利なのですが、
さすがに何を計算しているのか気になります。
今回は、perfcurve関数の中身を確認するため、
perfcurveなしでROC曲線を描いてみます。
目次
ROC曲線とは
ROC曲線とは、
Receiver Operating Characteristic曲線の略です。
今回の本題ではないのでさらっといきますが、
ある検査/分類器について、
横軸に偽陽性率、縦軸に真陽性率をとるグラフで、
しきい値(=陽性判定の基準値)を
任意に変化させたときに描かれる曲線
です。
機械学習では、
分類器の性能を評価するのに
用いられます。
水色の面積(AUC)が大きいほど
分類器の性能が高いことをあらわすことになります。
分類器/検証用データの例
ROC曲線は分類器の性能を評価する曲線です。
ですので、
評価対象の分類器と、検証用データが必要になります。
分類器
分類器は、適当にアプリで作りました。
線形サポートベクトルマシンです。
classificationSVM = fitcsvm(... predictors, ... response, ... 'KernelFunction', 'linear', ... 'PolynomialOrder', [], ... 'KernelScale', 'auto', ... 'BoxConstraint', 1, ... 'Standardize', true, ... 'ClassNames', [0; 1]);
学習用データpredictors,responseは提示していませんが、
4つの特徴量をいれると、'0'か'1'かを判定してくれる分類器です。
この分類器にテストデータをいれて
性能を評価してみようと思います。
検証用データ
今回は特徴量4つなので、
testdata=(100×5の配列)にしてみました。
被検者100人について、
特徴量:1-4列
5列目:'1'、'0'の教師情報(真のクラス)
をいれたデータです。
('1'=陰性、'0'=陽性と思ってください。)
このデータの
予測結果と、真のクラスから、
ROC曲線を描いて、分類器の性能を評価します。
ROC曲線を描くのに必要なデータ
まず、perfcurveを使ってみることを考えます。
必要な引数は3つあります。
[X,Y] = perfcurve(label,scores,posclass)
であり、
label:真のクラス=testdataの5列目
posclass:陽性のラベル=0
です。
あとはscoreですね。
分類スコア、事後確率
scoreに入る項目は
分類器のアルゴリズムによって異なりますが、
サポートベクトルマシンでは、
分類スコアと呼ばれる数値が入ります。
単純に言えば、
「分類の境界線からの符号付の距離」
になります。
しきい値が既定値なら、
分類スコア>0なら陽性
分類スコア<0なら陰性
です。
ベイズ分類器では、事後確率の大小関係で
分類しますので、
scoreには事後確率(0~1の範囲)が入ります。
しきい値が既定値なら
事後確率>0.5なら陽性
事後確率<0.5なら陰性
です。
実際の計算は、matlabにお任せで
%testdataから分類スコアを計算して予測。予測結果は~で省略。 %classificationSVMは分類器 [~,score]=predict(classificationSVM,testdata(1:4))
で計算してくれます。
ROC曲線を図示
さて、
perfcurveで計算したX,Yをplot(X,Y)で図示すると
が得られます。
実用上はこれで問題ないですが、
これから、どのようにしてこの曲線が得られるか
見ていきます。
分類スコアの昇順にデータを並べ替え
まずは、分類スコアと真のクラスを一つの表にまとめます。
%学習済み分類器を使って、各テストデータの分類スコアをゲットする %scoreの1列目は'0'に分類する分類スコア、2列目は'1'と判定する分類スコア [~,score]=predict(classificationSVM,testdata(:,1:4)); % 分類スコアと真のクラスをテーブルでドッキング score_class=table; score_class.score=score(:,1); score_class.true_Class=testdata(:,5);
そして、この表をscoreの小さい順に並べ替えます。
%1列目のscoreによって昇順に並べ替える score_class=sortrows(score_class);
しきい値を被検者1人分づつ変えていく
ROC曲線では、分類スコアのしきい値を変えつつ
真陽性率/偽陽性率を計算していきます。
しきい値の変化のさせ方は無限にありますが、
各被検者の分類スコアを超えない変化だと、
どのみち真陽性率/偽陽性率は変化しませんので
しきい値の変え方は、
「各被検者の中間」
にすれば十分です。
サポートベクトルマシンのしきい値は
既定値では0です(下図)
にしています。
しきい値をかえつつ計算
真陽性率/偽陽性率は定義に従い
計算するだけです。
%分類器しきい値を1被検者分ずつずらして、 %逐一真陽性率/偽陽性率を計算 num=height(score_class); %1列目に真陽性率、2列目に偽陽性率を格納する予定で宣言 true_falsePosRate=zeros(num,2); for i=1:num %真の'0'の数、真の'1'の数 true_count=nnz(score_class{:,2}==0); false_count=nnz(score_class{:,2}==1); %真に'0'で分類も'0'/真には'1'だけど分類は'0'の数 pred0andTrue=nnz(score_class{i:num,2}==0); pred0butFalse=nnz(score_class{i:num,2}==1); %真陽性率/偽陽性率を計算 true_falsePosRate(i,1)=pred0andTrue/true_count; true_falsePosRate(i,2)=pred0butFalse/false_count; end
図示
上で計算したデータから、ROC曲線を描きます。
横軸は偽陽性率、縦軸は真陽性率として
プロット(答え合わせするのでscatter)
してみます。
scatter(true_falsePosRate(:,2),true_falsePosRate(:,1));
となりました。
一致していますね。
まとめ
matlabには便利な関数がたくさんありますが、
内容がわかっていると、
変則的な処理の際に、応用が効きそうです。
検証用データの
「分類スコア」と「真のクラス」が
分かっていれば
ROC曲線が描ける
ということが実感できたかと思います。
「ROC曲線をかけ」
といわれて固まっている人がいたら
まず「分類スコア/事後確率」を求めてください。