今週の配付資料。グラフと表のみによるデータ解析と比較的単純な学習機械によるデータ解析に続いて、今回は次の2つの課題に取り組んでもらう。
PPDACの5つの要素のうち、Pが変わって、Dにデータが追加されて、Aも変更になる。
1回目と2回目とで、各手法に対する印象が少し異なってくると嬉しい。
例えばあるデータに回帰分析を行う。
tic.lm <- lm(V86~.,data=tic.learn)
学習理論の言葉では、これは「回帰分析」という学習機械を「最小二乗法」という学習アルゴリズムで学習させたことに相当する。 そして学習の精度は、「実際の個々の観測値(tic.learnV86, fitted(tic.lm),
xlab="V86", ylab="Fitted Value")
</code>
あまりよくわからないので、箱ひげ図に直してみる。
plot(fitted(tic.lm)~as.factor(tic.learn$V86), xlab="V86", ylab="Fitted Value")
ヒストグラムを描いてもいい。
par(mfrow=c(2,1)) hist(fitted(tic.lm)[tic.learn$V86==0], main="V86=0", xlab="Fitted Value") hist(fitted(tic.lm)[tic.learn$V86==1], main="V86=1", xlab="Fitted Value")
あまり変わらないように見える。 平均の差のt検定(Welchの検定)ぐらいをやってみると、この差に統計的な有意差はあることが分かる。
t.test(fitted(tic.lm)[tic.learn$V86==0],fitted(tic.lm)[tic.learn$V86==1],var.equal=F)
さりとて、当てはめ値が0付近なのはあまりよい回帰分析とは言えない。
当てはまりの良さ(悪さ)は、残差という量でも検討できる。残差の定義は、「実際の個々の観測値(tic.learnV86,residuals(tic.lm),
xlab="V86", ylab="Residuals")
</code> や、当てはめ値と残差の散布図
plot(fitted(tic.lm),residuals(tic.lm), xlab="Fitted Values", ylab="Residuals")
を見て、何か説明できていない傾向が残っていないかどうかを検討する。 他に、てこ比を見たり、半正規プロットなどを検討することもある。
重回帰分析に限って、上で紹介したグラフの多くは
plot(tic.lm)
で自動的に描画される。
他にも要約の出力
summary(tic.lm)
を見て、学習精度を検討する。
予測とは、学習した結果(学習済みの学習機械)を別のデータに基づく予測に用いることを言う。 そのためには、学習用データと同じ構造を持つ、別のデータを用意する。 予測精度を評価するので、ここでは評価用データと呼ぶ。 今年の実験ではtic.learnが学習用データ、tic.evalが評価用データであり、前回のデータ読み込みの手順で両方ともダウンロードされる。
予測値の算出には関数predictを用いる。学習済み機械tic.lmに、tic.evalの中の各レコードのV1からV85に基づいてV86を予測させるにはpredict()を
predict(tic.lm, newdata=tic.eval)
と用いる。学習にtic.evalを用いていないことから、この結果は予測値として扱える。
lmを用いて予測したので、
v86.lm <- predict(tic.lm, newdata=tic.eval)
と名付けておく。
plot(tic.eval$V86, v86.lm, xlab="V86", ylab="Predicted Value")
ヒストグラムを描いてもいい。
par(mfrow=c(2,1)) hist(v86.lm[tic.eval$V86==0], main="V86=0", xlab="Predicted Value") hist(v86.lm[tic.eval$V86==1], main="V86=1", xlab="Predicted Value")
なんかダメそうに見える。
さて残差は「当てはめ値-観測値」だったが、予測の良さを測るには予測誤差を用いる。 予測誤差の定義は「予測値-正解」である。
plot(tic.eval$V86, tic.eval$V86-v86.lm, xlab="V86", ylab="Prediction Error")
予測誤差にも傾向があり、とてもではないが、重回帰分析はこのままではよい予測を与えてくれる気がしない。 箱ひげ図を描くまでもないが、念のため。
plot((tic.eval$V86-v86.lm)~as.factor(tic.eval$V86), xlab="V86", ylab="Prediction Error")
あまり変わらないように見える。 平均の差のt検定(Welchの検定)ぐらいをやってみると、この差に統計的な有意差はあることが分かる。
t.test((tic.eval$V86-v86.lm)[tic.eval$V86==0], (tic.eval$V86-v86.lm)[tic.eval$V86==1], var.equal=F)
まあだめそう。。。
学習機械は予測精度が高くて初めて、有用性が認められる。そのためには「学習に用いなかったデータ」に関して予測を行い、精度を評価する必要がある。
例えば線形判別分析(lda)に学習用データ(tic.learn)を学習させるとする。
lda(V86~.,data=tic.learn)
その学習結果は次のようにオブジェクトに収めることができる。
tic.lda <- lda(V86~.,data=tic.learn)
これを用いて、評価用データ(lda.eval)に関するCARAVAN(V86)の予測を行うには、
predict(tic.lda,newdata=tic.eval)
を実行すれば良い。この結果もまたオブジェクトの中に収めることができる。
v86.lda <- predict(tic.lda,newdata=tic.eval)
v86.ldaは「リスト」と呼ばれるオブジェクトであり、
is.list(v86.lda)
を実行して、リストかどうかを尋ねるとTRUEが返ってくる。
リストの中身を見るにはnames関数を用いる。
names(v86.lda)
画面には次のように表示される。
> names(v86.lda) [1] "class" "posterior" "x"
これはv86.ldaの中には次の3つが入っていることを意味する。
オブジェクト名 | 中身 |
class | クラス |
posterior | 事後確率 |
x | 判別関数の値 |
この内訳は、学習に使用したアルゴリズム毎に異なる。
ここからが少し、問題。学習機械に基づく予測結果は
v86.lda$class
に収められている。ただしこれは因子(factor)オブジェクトであり、加減乗除ができない。
v86.lda$class+1
はエラーになる。そこで、正答率を出すには
table(v86.lda$class, tic.eval$V86)
のようにクロス集計を実行して、予測結果(v86.lda$class)と実際(tic.eval$V86)を比較する。
他の学習機械についても同様に
tic.qda <- qda(V86~.,data=tic.learn) v86.qda <- predict(tic.qda,newdata=tic.eval) table(v86.qda$class, tic.eval$V86)
などと、予測性能の評価が可能になる。ただし二次判別分析(qda)はエラーを表示して実行できない。この時は、エラーの内容から
tic.qda <- qda(V86~V1,data=tic.learn) tic.qda <- qda(V86~V1+V2,data=tic.learn) tic.qda <- qda(V86~V1+V2+V3,data=tic.learn) tic.qda <- qda(V86~V1+V2+V3+V4,data=tic.learn) tic.qda <- qda(V86~V1+V2+V3+V4+V5,data=tic.learn) tic.qda <- qda(V86~V1+V2+V3+V4+V5+V6,data=tic.learn)
などと、ひとつひとつ増やしていってみるか、例えば
tic.qda <- qda(V86~.,data=tic.learn[,c(1:30,86)])
のように最初の30変数を使って86番目を予測する、とするなどの工夫が必要になる。
再帰的分割(rpart)を用いる場合は、次のようなデータの変換が必要になる。
tic.learn.2 <- tic.learn tic.learn.2$V86 <- as.factor(tic.learn$V86)
V86を因子オブジェクト(factor)に変換すると、rpartが分類木を学習する。この変換をしないと、回帰木を学習してしまう。
tic.rpart <- rpart(V86~.,data=tic.learn.2) v86.rpart <- predict(tic.rpart,newdata=tic.eval,type="class") table(v86.rpart, tic.eval$V86)
rpartの制御はたとえば
tic.rpart <- rpart(V86~.,data=tic.learn.2, control=rpart.control(cp=0.00001, minsplit=5))
のように指定する。
誤判別率(誤った予測をした割合)などを算出しつつ、各学習機械の制御パラメータを調整してみよ。
ひとつ目の課題は、より柔軟な学習機械を適用してもらい、先週までの方法との違いを検討してもらう。こちらについては今回も、同志社大学の金(じん)先生が公開されてらっしゃる
を参考に、進めて欲しい。
サポートベクターマシン(ksvm)はkernlabパッケージに、バギング(bagging)はipredパッケージに、ブースト(ada)はadaパッケージに、ランダムフォレスト(randomForest)はrandomForestパッケージに、それぞれ含まれているので、まずは必要なパッケージをインストールする。
Sys.setenv("http_proxy"="http://130.153.8.19:8080/") install.packages("kernlab", dependencies=TRUE) library(kernlab) install.packages("ipred", dependencies=TRUE) library(ipred) install.packages("ada", dependencies=TRUE) library(ada) install.packages("randomForest", dependencies=TRUE) library(randomForest)
サポートベクターマシンに学習させる実行例:
tic.svm <- ksvm(V86~., data=tic.learn.2, kernel="rbfdot", kpar=list(sigma=0.01)) v86.svm <- predict(tic.svm, newdata=tic.eval) table(v86.svm,tic.eval$V86)
kparの中身を変更しないと、全く予測精度が稼げない感じ。
バギングに学習させる実行例:
tic.bagging <-bagging(V86~., data=tic.learn.2, nbagg=40) v86.bagging <- predict(tic.bagging,newdata=tic.eval,type= "class") table(v86.bagging, tic.eval$V86)
これもバッグの数が40でいいか分からない微妙な感じ。
Adaブーストに学習させる実行例:
tic.ada <- ada(V86~., data=tic.learn.2, iter=20) v86.ada <- predict(tic.ada, newdata=tic.eval, type= "vector") table(v86.ada, tic.eval$V86)
これも繰り返し数(iter)が20ではぜんぜんだめな感じ。
ランダムフォレストに学習させる実行例:
tic.randomForest <- randomForest(V86~., data=tic.learn.2) v86.randomForest <- predict(tic.randomForest, newdata=tic.eval) table(v86.randomForest, tic.eval$V86)
以上は「弱い学習機械」の指定と、個々の学習機械の設定パラメータが、デフォルトのままであることとは注意しておく。それぞれの予測結果を見れば、パラメータのチューニングが必要なことは明らか。
なお、この課題では「過学習」について言及していないが、過学習は大事な問題であるので、各自、少し調べて気にすることを進める。
2つ目の課題は、前回までのレポートの考察として、どのような顧客層に重点的にキャンペーンを展開するのがよいか、提案書を起草してもらう。「提案書」という書類の形式については、成書を参照するのがよいが、参考までに幾つかのウェブサイトへのリンクを掲げておく。
なおレポートには、訪問リストを生成するための手順を記述しておけばよく、訪問リストそのものの添付は不要である。また、最終的な提案に機械学習の結果を用いる場合は、以下の点に留意されたい。