差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

次のリビジョン
前のリビジョン
dmb:2011:q4 [2012/01/29 21:55] – created wataludmb:2011:q4 [不明な日付] (現在) – 外部編集 (不明な日付) 127.0.0.1
行 1: 行 1:
-=== データの説明 === +=== 元のデータの説明 === 
-== TIC 2000 ==+== TIC2000 ==
  
-<code> +[[http://kdd.ics.uci.edu/databases/tic/tic.data.html|tic.data.txt]]からの要約。 
-tic.leaan <- read.table("http://kdd.ics.uci.edu/databases/tic/ticdata2000.txt"+ 
-tic.eval <- read.table("http://kdd.ics.uci.edu/databases/tic/ticeval2000.txt") +  * CoIL 2000 Challengeで用いられた保険会社の顧客に関するデータ。86個の変数は、契約状況(V44-V85)と社会人口統計学的な変数(V1-V43)を含んでいる。この調査は "Can you predict who would be interested in buying a caravan insurance policy and give an explanation why?" という問いに答えるように集められた。 
-tic.test <read.table("http://kdd.ics.uci.edu/databases/tic/tictgts2000.txt") +  * このデータはオランダのデータマイニング会社Sentinent Machine Researchから提供され、現実のビジネスの問題に基づいている。学習用データ(ticdata2000.txt)は5000レコードでcaravan insurance policyの契約の有無(V86)を含んでおり、検証用データ(ticeval2000.txt)は4000レコードで契約の有無(V86)は含んでいない。検証用データの正解は、CoIL 2000 Challengeの開催時には公開されていなかったが、現在はテストデータ(tictest2000.txt)として公開されている。 
-tic.eval$V86 <- tic.test +  * V1-V43のうち、コード化が指定されていない変数はすべて、郵便番号の一桁目のエリアを指している。たとえばV30が9ならばその顧客は郵便番号が9で始まるエリアに家を借りていることを、V31が5ならば郵便番号が5のエリアに持ち家があることを意味する。職業、社会層などもすべて、該当するエリアの箇所が郵便番号の一桁目で埋まっている。
-rm(tic.test) +
-tic.learn$V1 <- as.factor(tic.learn$V1) +
-tic.lean$V5 <- as.factor(tic.learn$V5+
-</code>+
  
 == 変数 == == 変数 ==
 +
 +[[http://kdd.ics.uci.edu/databases/tic/dictionary.txt|dictionary.txt]]からの抜粋と要約、の日本語版。
 +
 |変数|分類|メモ| |変数|分類|メモ|
 |V1|顧客分類2|L0でコード化されている、数字の大きさに意味なし| |V1|顧客分類2|L0でコード化されている、数字の大きさに意味なし|
行 20: 行 19:
 |V5|顧客分類1|L2でコード化されている、数字の大きさに意味なし| |V5|顧客分類1|L2でコード化されている、数字の大きさに意味なし|
 |V6-V9|宗教|L3でコード化されている、V6+V7+V8+V9は9から12の間。それぞれの宗教を信じる割合?| |V6-V9|宗教|L3でコード化されている、V6+V7+V8+V9は9から12の間。それぞれの宗教を信じる割合?|
-|V10-V13|結婚|L3でコード化されている?割合?| +|V10-V13|結婚|場所を表す変数, 例えばV10が0ならば無し?| 
-|V14-V15|世帯の大きさ|L3でコード化されているV14+V15は10以下。割合?| +|V14-V15|世帯の大きさ|L3でコード化されている、なぜかV14+V15は10以下。割合?| 
-|V16-V18|教育水準|L3でコード化されているV16+V17+V18はほぼ10、それぞれの年数?割合?| +|V16-V18|教育水準|L3でコード化されている、なぜかV16+V17+V18はほぼ10、それぞれの年数?割合?| 
-|V19-V24|職業|L3でコード化されているV19+V20+V21+V22+V23+V24は9から13の間| +|V19-V24|職業|L3でコード化されている、なぜかV19+V20+V21+V22+V23+V24は9から13の間| 
-|V25-V29|社会層|L3でコード化されているV25+V26+V27+V28+V29は9から12の間| +|V25-V29|社会層|L3でコード化されている、なぜかV25+V26+V27+V28+V29は9から12の間| 
-|V30-V31|住居|L3でコード化されているV30+V31は9か10| +|V30-V31|住居|L3でコード化されている、なぜかV30+V31は9か10| 
-|V32-V34|自動車|L3でコード化されているV32+V33+V34は9から11の間| +|V32-V34|自動車|L3でコード化されている、なぜかV32+V33+V34は9から11の間| 
-|V35-V36|健康保険|L3でコード化されているV35+V36は9か10| +|V35-V36|健康保険|L3でコード化されている、なぜかV35+V36は9か10| 
-|V37-V41|収入|L3でコード化されているV37+V38+V39+V40+V41は9から13の間| +|V37-V41|収入|L3でコード化されている、なぜかV37+V38+V39+V40+V41は9から13の間| 
-|V42|平均収入|L3でコード化されている+|V42|平均収入|L3でコード化されている| 
-|V43|購買力|L3でコード化されている1から8の間。|+|V43|購買力|L3でコード化されている1から8の間。|
 |V44-V64|各種保険支払い額|L4でコード化| |V44-V64|各種保険支払い額|L4でコード化|
 |V65-V85|各種保険契約件数|件数| |V65-V85|各種保険契約件数|件数|
  
 メモの確認用のコード。 メモの確認用のコード。
-<code>+
 <code> <code>
 table((tic.learn$V16+tic.learn$V17+tic.learn$V18)) table((tic.learn$V16+tic.learn$V17+tic.learn$V18))
行 46: 行 45:
 </code> </code>
  
-</code> 
  
 == 各変数のコーディング == == 各変数のコーディング ==
行 142: 行 140:
 |8|f 10.000 - 19.999| |8|f 10.000 - 19.999|
 |9|f 20.000 - ?| |9|f 20.000 - ?|
 +
 +== 参考 ==
 +
 +kernlabパッケージに、加工済みのデータが入っていて、それを使うこともできる。
 +
 +<code>
 +install.packages(c("kernlab"), dependencies=TRUE)
 +tic.learn <- ticdata[1:5822,]
 +tic.eval <- ticdata[5823:9822,]
 +</code>
 +
 +=== 今回の課題 ===
 +== 概要 ==
 +
 +  * もっと大きな変数の組み合わせで、同じ事を試みよ。その際に生じる幾つかの困難を乗り越えよ。
 +  * CoIL 2000では、訪問する800人を選べ、という課題になっていたが、この課題では訪問する人数も各自で決めて良い。
 +
 +== 準備 ==
 +
 +<code>
 +install.packages(c("mvpart", "gam", "kernlab"), dependencies=TRUE)
 +</code>
 +
 +これでエラーが出る場合には、[[https://appl.stat.inf.uec.ac.jp/doku.php?id=r:how_to:internet_proxy|プロキシの設定]]を試みると良い。
 +
 +<code>
 +library(mvpart)
 +library(gam)
 +library(MASS)
 +library(kernlab)
 +</code>
 +
 +以上の4つのライブラリを、この課題では使う可能性がある。
 +
 +== データの読み込み ==
 +
 +<code>
 +tic.leaan <- read.table("http://kdd.ics.uci.edu/databases/tic/ticdata2000.txt")
 +tic.eval <- read.table("http://kdd.ics.uci.edu/databases/tic/ticeval2000.txt")
 +tic.test <- read.table("http://kdd.ics.uci.edu/databases/tic/tictgts2000.txt")
 +tic.eval <- cbind(tic.eval, tic.test)
 +colnames(tic.eval)[86] <- "V86"
 +rm(tic.test)
 +</code>
 +
 +== 少し加工する ==
 +
 +以下の6行は、実行しない方がいい場合もある。
 +
 +<code>
 +tic.learn$V1 <- as.factor(tic.learn$V1)
 +tic.learn$V5 <- as.factor(tic.learn$V5)
 +tic.learn$V86 <- as.factor(tic.learn$V86)
 +tic.eval$V1 <- as.factor(tic.eval$V1)
 +tic.eval$V5 <- as.factor(tic.eval$V5)
 +tic.eval$V86 <- as.factor(tic.eval$V86)
 +</code>
 +
 +あとはそのまま。
 +
 +== 考えたルールに基づく対象限定 ==
 +
 +各変数に閾値を設けてルールを生成したとする。
 +たとえば、「V47が5.5以上かつV44が1未満」または「V47が5.5以上かつV1が{1,3,6,8,12,20}のどれか」、というルールは
 +次のように記す。
 +
 +<code>
 +(tic.eval$V47>5.5 & tic.eval$V44<1) | (tic.eval$V47>5.5 & (tic.eval$V1==1 |tic.eval$V1==3 | tic.eval$V1==6 | tic.eval$V1==8 | tic.eval$V1==12 | tic.eval$V1==20) ) 
 +</code>
 +
 +「&」が「かつ(AND)」、「|」が「または(OR)」である。
 +
 +このルールを検証用データに適用するには、
 +
 +<code>
 +tic.eval.visit <- (tic.eval$V47>5.5 & tic.eval$V44<1) | (tic.eval$V47>5.5 & (tic.eval$V1==1 |tic.eval$V1==3 | tic.eval$V1==6 | tic.eval$V1==8 | tic.eval$V1==12 | tic.eval$V1==20) ) 
 +</code>
 +
 +と、訪問するか否かを二値(TRUE, FALSE)で表すオブジェクトを生成する。
 +このモデルに予測に基づいた訪問の成果を検証するには、訪問対象のリストtic.visitと検証用データの正解V86のクロス集計を行えばよい。
 +
 +<code>
 +table(tic.eval.visit)
 +
 +FALSE  TRUE 
 + 3029   971 
 +
 +table(tic.eval.visit, tic.eval$V86)
 +
 +tic.eval.visit    0    1
 +         FALSE 2878  151
 +         TRUE   884   87
 +</code>
 +
 +ここでは、訪問対象に884+87=971人を選定し、そのうちの87人が実際に契約してくれる人だったことになる。
 +契約率は87/971=8.96%。また誤判別率は
 +<code>
 +(884+151)/4000
 +</code>
 +で25.9%となる。
 +
 +== モデルに基づく対象限定 ==
 +
 +学習したモデルに基づいて、訪問対象を狭めるには、predict()という関数を用いて、訪問対象か否かというリストを作成する。
 +まず、設定まで調整したモデルを、学習用データ(tic.learn)から得る。
 +
 +<code>
 +tic.rpart <- rpart(V86~., data=tic.learn, control=c(cp=0.005))
 +</code>
 +
 +次に、このモデル(ここではtic.rpart)を検証用データ(tic.eval)に適用して、契約してくれるか否かの予測を行う。
 +この際、0.05という閾値も調整の必要がある。
 +
 +<code>
 +tic.eval.visit <- predict(tic.rpart, newdata=tic.eval)[,2]>0.05
 +</code>
 +
 +このモデルに予測に基づいた訪問の成果を検証するには、訪問対象のリストtic.visitと検証用データの正解V86のクロス集計を行えばよい。
 +
 +<code>
 +table(tic.eval.visit)
 +
 +tic.eval.visit 
 +FALSE  TRUE
 + 2389  1611
 +
 +table(tic.eval.visit, tic.eval$V86)
 +
 +tic.eval.visit    0    1
 +         FALSE 2310   79
 +         TRUE  1452  159
 +</code>
 +
 +ここでは、訪問対象に1452+159=1611人を選定し、そのうちの159人が実際に契約してくれる人だったことになる。契約率は159/1452=11.0%。
 +また誤判別率は
 +<code>
 +(79+1452)/4000
 +</code>
 +で38.275%となる。
 +
 +== 想定される困難 ==
 +
 +次の1行を実行すると、かなり時間がかかってエラーになる。
 +<code>
 +tic.glm.step <- step(glm(V86~., family="binomial", data=tic.learn)
 +</code>
 +
 +次の4行、いずれもエラーになる。変数間の関係が悪すぎるよう。変数の意味を考えて、追加しないといけないかも。
 +
 +<code>
 +tic.glm <- glm(V86~V1+V2+V3+V4+V5+V6+V7+V8+   V10+
 +V11+V12+    V14+    V16+V17+    V19+V20+
 +V21+V22+V23+    V25+V26+V27+V28+    V30+
 +        V33+V34+V35+    V37+V38+V39+V40+
 +    V42+V43+V44+V45+V46+V47+V48+V49+V50+
 +V51+V52+V53+V54+V55+V56+V57+V58+V59+V60+
 +V61+V62+V63+V64+V65+V66+V67+V68+V69+V70+
 +V71+V72+V73+V74+V75+V76+V77+V78+V79+V80+
 +V81+V82+V83+V84+V85, family="binomial", data=tic.learn)
 +table(predict(tic.glm, newdata=tic.eval)>0.5)
 +</code>
 +
 +<code>
 +tic.glm <- glm(V86~     V2+V3+V4+    V6+V7+V8+   V10+
 +V11+V12+    V14+    V16+V17+    V19+V20+
 +V21+V22+V23+    V25+V26+V27+V28+    V30+
 +        V33+V34+V35+    V37+V38+V39+V40+
 +    V42+V43+V44+V45+V46+V47+V48+V49+V50+
 +V51+V52+V53+V54+V55+V56+V57+V58+V59+V60+
 +V61+V62+V63+V64+V65+V66+V67+V68+V69+V70+
 +V71+V72+V73+V74+V75+V76+V77+V78+V79+V80+
 +V81+V82+V83+V84+V85, family="binomial", data=tic.learn)
 +</code>
 +
 +<code>
 +tic.glm <- glm(V86~V44+V45+V46+V47+V48+V49+V50+
 +V51+V52+V53+V54+V55+V56+V57+V58+V59+V60+
 +V61+V62+V63+V64+V65+V66+V67+V68+V69+V70+
 +V71+V72+V73+V74+V75+V76+V77+V78+V79+V80+
 +V81+V82+V83+V84+V85, family="binomial", data=tic.learn)
 +</code>
 +
 +<code>
 +tic.glm <- glm(V86~V44+V45+V46+V47+V48+V49+V50+
 +V51+V52+V53+V54+V55+V56+V57+V58+V59+V60+
 +V61+V62+V63+V64, family="binomial", data=tic.learn)
 +</code>
 +
 +次の1行を実行すると、不契約ばかり。
 +<code>
 +tic.rpart <- rpart(V86~., data=tic.learn)
 +</code>
 +
 +次の1行は、動かない。
 +<code>
 +tic.gam <- gam(V86~V1+s(V2)+s(V3)+s(V4)+V5+s(V6)+s(V7)+s(V8)+s(V9)+s(V10)+
 +s(V11)+s(V12)+s(V13)+s(V14)+s(V15)+s(V16)+s(V17)+s(V18)+s(V19)+s(V20)+
 +s(V21)+s(V22)+s(V23)+s(V24)+s(V25)+s(V26)+s(V27)+s(V28)+s(V29)+s(V30)+
 +s(V31)+s(V32)+s(V33)+s(V34)+s(V35)+s(V36)+s(V37)+s(V38)+s(V39)+s(V40)+
 +s(V41)+s(V42)+s(V43)+s(V44)+s(V45)+s(V46)+s(V47)+s(V48)+s(V49)+s(V50)+
 +s(V51)+s(V52)+s(V53)+s(V54)+s(V55)+s(V56)+s(V57)+s(V58)+s(V59)+s(V60)+
 +s(V61)+s(V62)+s(V63)+s(V64)+s(V65)+s(V66)+s(V67)+s(V68)+s(V69)+s(V70)+
 +s(V71)+s(V72)+s(V73)+s(V74)+s(V75)+s(V76)+s(V77)+s(V78)+s(V79)+s(V80)+
 +s(V81)+s(V82)+s(V83)+s(V84)+s(V85), family="binomial", data=tic.learn)
 +</code>
 +
 +s()が使えるのはデータが4種類以上ある時だけ、というメッセージが出るので、各変数の値の数を数えて、3個以下のものだけ表示させてみる。
 +<code>
 +for( j in c(1:86) ) {
 +  tmp <- table(tic.learn[,j])
 +  if(dim(tmp)<4) {
 +    print(j)
 +    print(tmp)
 +  }
 +}
 +</code>
 +
 +これを反映させると、こうなる。
 +<code>
 +tic.gam <- gam(V86~V1+s(V2)+s(V3)+s(V4)+V5+s(V6)+s(V7)+s(V8)+s(V9)+s(V10)+
 +s(V11)+s(V12)+s(V13)+s(V14)+s(V15)+s(V16)+s(V17)+s(V18)+s(V19)+s(V20)+
 +s(V21)+s(V22)+s(V23)+s(V24)+s(V25)+s(V26)+s(V27)+s(V28)+s(V29)+s(V30)+
 +s(V31)+s(V32)+s(V33)+s(V34)+s(V35)+s(V36)+s(V37)+s(V38)+s(V39)+s(V40)+
 +s(V41)+s(V42)+s(V43)+s(V44)+s(V45)+s(V46)+s(V47)+s(V48)+s(V49)+s(V50)+
 +s(V51)+s(V52)+s(V53)+s(V54)+s(V55)+s(V56)+  V57 +s(V58)+s(V59)+  V60 +
 +s(V61)+  V62 +s(V63)+s(V64)+  V65 +  V66 +  V67 +s(V68)+s(V69)+s(V70)+
 +s(V71)+s(V72)+s(V73)+s(V74)+  V75 +s(V76)+  V77 +  V78 +  V79 +s(V80)+
 +  V81 +  V82 +s(V83)+  V84 +  V85 , family="binomial", data=tic.learn)
 +</code>
 +
 +さらにここから次の1行を実行すると、エラーになる。
 +<code>
 +tic.gam.step <- step(gam(V86~V1+s(V2)+s(V3)+s(V4)+V5+s(V6)+s(V7)+s(V8)+s(V9)+s(V10)+
 +s(V11)+s(V12)+s(V13)+s(V14)+s(V15)+s(V16)+s(V17)+s(V18)+s(V19)+s(V20)+
 +s(V21)+s(V22)+s(V23)+s(V24)+s(V25)+s(V26)+s(V27)+s(V28)+s(V29)+s(V30)+
 +s(V31)+s(V32)+s(V33)+s(V34)+s(V35)+s(V36)+s(V37)+s(V38)+s(V39)+s(V40)+
 +s(V41)+s(V42)+s(V43)+s(V44)+s(V45)+s(V46)+s(V47)+s(V48)+s(V49)+s(V50)+
 +s(V51)+s(V52)+s(V53)+s(V54)+s(V55)+s(V56)+  V57 +s(V58)+s(V59)+  V60 +
 +s(V61)+  V62 +s(V63)+s(V64)+  V65 +  V66 +  V67 +s(V68)+s(V69)+s(V70)+
 +s(V71)+s(V72)+s(V73)+s(V74)+  V75 +s(V76)+  V77 +  V78 +  V79 +s(V80)+
 +  V81 +  V82 +s(V83)+  V84 +  V85 , family="binomial", data=tic.learn)
 +</code>
 +
 +=== おまけ ===
 +
 +AdaBoostを適用するには、adaパッケージをインストールする。
 +<code>
 +install.packages(c("ada"), dependencies=TRUE)
 +</code>
 +
 +決定木を弱学習機械として用いるには例えば、
 +<code>
 +tic.ada <- ada(V86~., 
 +  data=tic.learn, 
 +  iter=100, 
 +  control=rpart.control(maxdepth=1, cp=-1, minsplit=0))
 +</code>
 +とする。rpart.controlの中身は、
 +  * maxdepth=1が1回だけ分岐せよ
 +  * cp=-1は不純度によらず必ず分岐せよ
 +  * minsplit=0は親ノードのレコード数が幾つでも必ず分岐せよ
 +と、必ず1段の決定木を学習で得ること、と指定されている。
 +
 +これでiterとmaxdepthを変えると、もしかして良い訪問案が学習できるかもしれない?
 +ただしこの二つのパラメータを大きくすると、計算時間が増大するので要注意。
 +iterに比例し、2のmaxdepth乗にも比例して、増えていく。