元のデータの説明
TIC2000
tic.data.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?” という問いに答えるように集められた。
- このデータはオランダのデータマイニング会社Sentinent Machine Researchから提供され、現実のビジネスの問題に基づいている。学習用データ(ticdata2000.txt)は5000レコードでcaravan insurance policyの契約の有無(V86)を含んでおり、検証用データ(ticeval2000.txt)は4000レコードで契約の有無(V86)は含んでいない。検証用データの正解は、CoIL 2000 Challengeの開催時には公開されていなかったが、現在はテストデータ(tictest2000.txt)として公開されている。
- V1-V43のうち、コード化が指定されていない変数はすべて、郵便番号の一桁目のエリアを指している。たとえばV30が9ならばその顧客は郵便番号が9で始まるエリアに家を借りていることを、V31が5ならば郵便番号が5のエリアに持ち家があることを意味する。職業、社会層などもすべて、該当するエリアの箇所が郵便番号の一桁目で埋まっている。
変数
dictionary.txtからの抜粋と要約、の日本語版。
変数 | 分類 | メモ |
V1 | 顧客分類2 | L0でコード化されている、数字の大きさに意味なし |
V2 | 住居数 | 大きいほど住む箇所が多い |
V3 | 世帯構成員数の平均 | 人数 |
V4 | 世帯構成員の平均年齢 | L1でコード化されている、年齢 |
V5 | 顧客分類1 | L2でコード化されている、数字の大きさに意味なし |
V6-V9 | 宗教 | L3でコード化されている、V6+V7+V8+V9は9から12の間。それぞれの宗教を信じる割合? |
V10-V13 | 結婚 | 場所を表す変数, 例えばV10が0ならば無し? |
V14-V15 | 世帯の大きさ | L3でコード化されている、なぜかV14+V15は10以下。割合? |
V16-V18 | 教育水準 | L3でコード化されている、なぜかV16+V17+V18はほぼ10、それぞれの年数?割合? |
V19-V24 | 職業 | L3でコード化されている、なぜかV19+V20+V21+V22+V23+V24は9から13の間 |
V25-V29 | 社会層 | L3でコード化されている、なぜかV25+V26+V27+V28+V29は9から12の間 |
V30-V31 | 住居 | L3でコード化されている、なぜかV30+V31は9か10 |
V32-V34 | 自動車 | L3でコード化されている、なぜかV32+V33+V34は9から11の間 |
V35-V36 | 健康保険 | L3でコード化されている、なぜかV35+V36は9か10 |
V37-V41 | 収入 | L3でコード化されている、なぜかV37+V38+V39+V40+V41は9から13の間 |
V42 | 平均収入 | L3でコード化されている |
V43 | 購買力 | L3でコード化されている、1から8の間。 |
V44-V64 | 各種保険支払い額 | L4でコード化 |
V65-V85 | 各種保険契約件数 | 件数 |
メモの確認用のコード。
table((tic.learn$V16+tic.learn$V17+tic.learn$V18)) table((tic.learn$V19+tic.learn$V20+tic.learn$V21+tic.learn$V22+tic.learn$V23+tic.learn$V24)) table((tic.learn$V25+tic.learn$V26+tic.learn$V27+tic.learn$V28+tic.learn$V29)) table(tic.learn$V30+tic.learn$V31) table(tic.learn$V32+tic.learn$V33+tic.learn$V34) table(tic.learn$V35+tic.learn$V36) table(tic.learn$V37+tic.learn$V38+tic.learn$V39+tic.learn$V40+tic.learn$V41)
各変数のコーディング
L0:分類を表す数字なので、大小関係に意味がなく、名義尺度である。そのままでは説明変数にならない。
Value | Label |
1 | High Income, expensive child |
2 | Very Important Provincials |
3 | High status seniors |
4 | Affluent senior apartments |
5 | Mixed seniors |
6 | Career and childcare |
7 | Dinki's (double income no kids) |
8 | Middle class families |
9 | Modern, complete families |
10 | Stable family |
11 | Family starters |
12 | Affluent young families |
13 | Young all american family |
14 | Junior cosmopolitan |
15 | Senior cosmopolitans |
16 | Students in apartments |
17 | Fresh masters in the city |
18 | Single youth |
19 | Suburban youth |
20 | Etnically diverse |
21 | Young urban have-nots |
22 | Mixed apartment dwellers |
23 | Young and rising |
24 | Young, low educated |
25 | Young seniors in the city |
26 | Own home elderly |
27 | Seniors in apartments |
28 | Residential elderly |
29 | Porchless seniors: no front yard |
30 | Religious elderly singles |
31 | Low income catholics |
32 | Mixed seniors |
33 | Lower class large families |
34 | Large family, employed child |
35 | Village families |
36 | Couples with teens 'Married with children' |
37 | Mixed small town dwellers |
38 | Traditional families |
39 | Large religous families |
40 | Large family farms |
41 | Mixed rurals |
L1:大きさが年齢の順なので、そのまま説明変数に使える。
1 | 20-30 years |
2 | 30-40 years |
3 | 40-50 years |
4 | 50-60 years |
5 | 60-70 years |
6 | 70-80 years |
L2:数字は分類を表すだけなので、連続尺度でも順序尺度でもなく、名義尺度。そのままでは説明変数にならない。
1 | Successful hedonists |
2 | Driven Growers |
3 | Average Family |
4 | Career Loners |
5 | Living well |
6 | Cruising Seniors |
7 | Retired and Religeous |
8 | Family with grown ups |
9 | Conservative families |
10 | Farmers |
L3:順序尺度。このまま連続尺度の説明変数として用いる。
0 | 0% |
1 | 1 - 10% |
2 | 11 - 23% |
3 | 24 - 36% |
4 | 37 - 49% |
5 | 50 - 62% |
6 | 63 - 75% |
7 | 76 - 88% |
8 | 89 - 99% |
9 | 100% |
L4: 順序尺度。今回はこのまま連続尺度の変数として用いる。
0 | f 0 |
1 | f 1 - 49 |
2 | f 50 - 99 |
3 | f 100 - 199 |
4 | f 200 - 499 |
5 | f 500 - 999 |
6 | f 1000 - 4999 |
7 | f 5000 - 9999 |
8 | f 10.000 - 19.999 |
9 | f 20.000 - ? |
参考
kernlabパッケージに、加工済みのデータが入っていて、それを使うこともできる。
install.packages(c("kernlab"), dependencies=TRUE) tic.learn <- ticdata[1:5822,] tic.eval <- ticdata[5823:9822,]
今回の課題
概要
- もっと大きな変数の組み合わせで、同じ事を試みよ。その際に生じる幾つかの困難を乗り越えよ。
- CoIL 2000では、訪問する800人を選べ、という課題になっていたが、この課題では訪問する人数も各自で決めて良い。
準備
install.packages(c("mvpart", "gam", "kernlab"), dependencies=TRUE)
これでエラーが出る場合には、プロキシの設定を試みると良い。
library(mvpart) library(gam) library(MASS) library(kernlab)
以上の4つのライブラリを、この課題では使う可能性がある。
データの読み込み
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)
少し加工する
以下の6行は、実行しない方がいい場合もある。
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)
あとはそのまま。
考えたルールに基づく対象限定
各変数に閾値を設けてルールを生成したとする。 たとえば、「V47が5.5以上かつV44が1未満」または「V47が5.5以上かつV1が{1,3,6,8,12,20}のどれか」、というルールは 次のように記す。
(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) )
「&」が「かつ(AND)」、「|」が「または(OR)」である。
このルールを検証用データに適用するには、
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) )
と、訪問するか否かを二値(TRUE, FALSE)で表すオブジェクトを生成する。 このモデルに予測に基づいた訪問の成果を検証するには、訪問対象のリストtic.visitと検証用データの正解V86のクロス集計を行えばよい。
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
ここでは、訪問対象に884+87=971人を選定し、そのうちの87人が実際に契約してくれる人だったことになる。 契約率は87/971=8.96%。また誤判別率は
(884+151)/4000
で25.9%となる。
モデルに基づく対象限定
学習したモデルに基づいて、訪問対象を狭めるには、predict()という関数を用いて、訪問対象か否かというリストを作成する。 まず、設定まで調整したモデルを、学習用データ(tic.learn)から得る。
tic.rpart <- rpart(V86~., data=tic.learn, control=c(cp=0.005))
次に、このモデル(ここではtic.rpart)を検証用データ(tic.eval)に適用して、契約してくれるか否かの予測を行う。 この際、0.05という閾値も調整の必要がある。
tic.eval.visit <- predict(tic.rpart, newdata=tic.eval)[,2]>0.05
このモデルに予測に基づいた訪問の成果を検証するには、訪問対象のリストtic.visitと検証用データの正解V86のクロス集計を行えばよい。
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
ここでは、訪問対象に1452+159=1611人を選定し、そのうちの159人が実際に契約してくれる人だったことになる。契約率は159/1452=11.0%。 また誤判別率は
(79+1452)/4000
で38.275%となる。
想定される困難
次の1行を実行すると、かなり時間がかかってエラーになる。
tic.glm.step <- step(glm(V86~., family="binomial", data=tic.learn)
次の4行、いずれもエラーになる。変数間の関係が悪すぎるよう。変数の意味を考えて、追加しないといけないかも。
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)
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)
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)
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)
次の1行を実行すると、不契約ばかり。
tic.rpart <- rpart(V86~., data=tic.learn)
次の1行は、動かない。
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)
s()が使えるのはデータが4種類以上ある時だけ、というメッセージが出るので、各変数の値の数を数えて、3個以下のものだけ表示させてみる。
for( j in c(1:86) ) { tmp <- table(tic.learn[,j]) if(dim(tmp)<4) { print(j) print(tmp) } }
これを反映させると、こうなる。
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)
さらにここから次の1行を実行すると、エラーになる。
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)
おまけ
AdaBoostを適用するには、adaパッケージをインストールする。
install.packages(c("ada"), dependencies=TRUE)
決定木を弱学習機械として用いるには例えば、
tic.ada <- ada(V86~., data=tic.learn, iter=100, control=rpart.control(maxdepth=1, cp=-1, minsplit=0))
とする。rpart.controlの中身は、
- maxdepth=1が1回だけ分岐せよ
- cp=-1は不純度によらず必ず分岐せよ
- minsplit=0は親ノードのレコード数が幾つでも必ず分岐せよ
と、必ず1段の決定木を学習で得ること、と指定されている。
これでiterとmaxdepthを変えると、もしかして良い訪問案が学習できるかもしれない? ただしこの二つのパラメータを大きくすると、計算時間が増大するので要注意。 iterに比例し、2のmaxdepth乗にも比例して、増えていく。