決定木とランダム森林のR言語実現


1.partyパッケージで意思決定ツリーを構築する
irisデータセットを例に挙げます.
ctree()で決定ツリーを構築し、predict()で新しいデータを予測します.
トレーニングセットとテストセットの区分:
> str(iris)
'data.frame':	150 obs. of  5 variables:
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
> set.seed(1234)
> ind  trainData  testData 
デフォルトパラメータを使用して決定ツリーを作成します.
> library(party)
> myFormula  iris_ctree  # check the prediction
> table(predict(iris_ctree), trainData$Species)
            
             setosa versicolor virginica
  setosa         40          0         0
  versicolor      0         37         3
  virginica       0          1        31
ルールを出力し、構築された決定ツリーを描画して表示します.
> print(iris_ctree)

	 Conditional inference tree with 4 terminal nodes

Response:  Species 
Inputs:  Sepal.Length, Sepal.Width, Petal.Length, Petal.Width 
Number of observations:  112 

1) Petal.Length <= 1.9; criterion = 1, statistic = 104.643
  2)*  weights = 40 
1) Petal.Length > 1.9
  3) Petal.Width <= 1.7; criterion = 1, statistic = 48.939
    4) Petal.Length <= 4.4; criterion = 0.974, statistic = 7.397
      5)*  weights = 21 
    4) Petal.Length > 4.4
      6)*  weights = 19 
  3) Petal.Width > 1.7
    7)*  weights = 32 
> plot(iris_ctree)
> #  
> plot(iris_ctree, type="simple")
> # 
構築された決定ツリーをテストセットでテストします.
> # predict on test data
> testPred  table(testPred, testData$Species)
            
testPred     setosa versicolor virginica
  setosa         10          0         0
  versicolor      0         12         2
  virginica       0          0        14

注意すべき点:
①ctree()は欠落値をうまく処理できず,欠落値を含む観測は左サブツリーに分割されたり右サブツリーに分割されたりするが,これは欠落値の代替規則によって決まる.
2トレーニングセットとテストセットは、決定ツリーが最終的にすべての変数を使用したかどうかにかかわらず、同じデータセットから作成する必要があります.すなわち、テーブル構造、含まれる変数は一致します.
3訓練セットと試験セットの分類変数のレベル値が一致しない場合、試験セットの予測が認識される.この問題を解決する方法は,テストセットの分類変数の水平値に基づいて訓練データを明示的に設定することである.2.rparパッケージで意思決定ツリーを構築する
bodyfatデータセットを例に挙げます.rpart()を使用して決定ツリーを構築し、最小予測誤差を持つ決定ツリーを選択し、predict()を使用して新しいデータを予測できます.
まず、データを表示します.
> data("bodyfat", package = "TH.data")
> dim(bodyfat)
[1] 71 10
> attributes(bodyfat)
$names
 [1] "age"          "DEXfat"       "waistcirc"    "hipcirc"      "elbowbreadth"
 [6] "kneebreadth"  "anthro3a"     "anthro3b"     "anthro3c"     "anthro4"     

$row.names
 [1] "47"  "48"  "49"  "50"  "51"  "52"  "53"  "54"  "55"  "56"  "57"  "58"  "59"  "60" 
[15] "61"  "62"  "63"  "64"  "65"  "66"  "67"  "68"  "69"  "70"  "71"  "72"  "73"  "74" 
[29] "75"  "76"  "77"  "78"  "79"  "80"  "81"  "82"  "83"  "84"  "85"  "86"  "87"  "88" 
[43] "89"  "90"  "91"  "92"  "93"  "94"  "95"  "96"  "97"  "98"  "99"  "100" "101" "102"
[57] "103" "104" "105" "106" "107" "108" "109" "110" "111" "112" "113" "114" "115" "116"
[71] "117"

$class
[1] "data.frame"

> bodyfat[1:5,]
   age DEXfat waistcirc hipcirc elbowbreadth kneebreadth anthro3a anthro3b anthro3c
47  57  41.68     100.0   112.0          7.1         9.4     4.42     4.95     4.50
48  65  43.29      99.5   116.5          6.5         8.9     4.63     5.01     4.48
49  59  35.41      96.0   108.5          6.2         8.9     4.12     4.74     4.60
50  58  22.79      72.0    96.5          6.1         9.2     4.03     4.48     3.91
51  60  36.42      89.5   100.5          7.1        10.0     4.24     4.68     4.15
   anthro4
47    6.13
48    6.37
49    5.82
50    5.66
51    5.91
トレーニングセットとテストセットの区分、およびモデルトレーニング:
> set.seed(1234)
> ind  bodyfat.train  bodyfat.test  # train a decision tree
> library(rpart)
> myFormula  bodyfat_rpart  attributes(bodyfat_rpart)
$names
 [1] "frame"               "where"               "call"               
 [4] "terms"               "cptable"             "method"             
 [7] "parms"               "control"             "functions"          
[10] "numresp"             "splits"              "variable.importance"
[13] "y"                   "ordered"            

$xlevels
named list()

$class
[1] "rpart"

> print(bodyfat_rpart$cptable)
          CP nsplit  rel error    xerror       xstd
1 0.67272638      0 1.00000000 1.0194546 0.18724382
2 0.09390665      1 0.32727362 0.4415438 0.10853044
3 0.06037503      2 0.23336696 0.4271241 0.09362895
4 0.03420446      3 0.17299193 0.3842206 0.09030539
5 0.01708278      4 0.13878747 0.3038187 0.07295556
6 0.01695763      5 0.12170469 0.2739808 0.06599642
7 0.01007079      6 0.10474706 0.2693702 0.06613618
8 0.01000000      7 0.09467627 0.2695358 0.06620732
> print(bodyfat_rpart)
n= 56 

node), split, n, deviance, yval
      * denotes terminal node

 1) root 56 7265.0290000 30.94589  
   2) waistcirc< 88.4 31  960.5381000 22.55645  
     4) hipcirc< 96.25 14  222.2648000 18.41143  
       8) age< 60.5 9   66.8809600 16.19222 *
       9) age>=60.5 5   31.2769200 22.40600 *
     5) hipcirc>=96.25 17  299.6470000 25.97000  
      10) waistcirc< 77.75 6   30.7345500 22.32500 *
      11) waistcirc>=77.75 11  145.7148000 27.95818  
        22) hipcirc< 99.5 3    0.2568667 23.74667 *
        23) hipcirc>=99.5 8   72.2933500 29.53750 *
   3) waistcirc>=88.4 25 1417.1140000 41.34880  
     6) waistcirc< 104.75 18  330.5792000 38.09111  
      12) hipcirc< 109.9 9   68.9996200 34.37556 *
      13) hipcirc>=109.9 9   13.0832000 41.80667 *
     7) waistcirc>=104.75 7  404.3004000 49.72571 *
決定ツリーのグラフを描画します.
> plot(bodyfat_rpart)
> text(bodyfat_rpart, use.n=T)
> # 
最小予測誤差を持つ決定ツリーを選択:
> opt  cp  bodyfat_prune  print(bodyfat_prune)
n= 56 

node), split, n, deviance, yval
      * denotes terminal node

 1) root 56 7265.02900 30.94589  
   2) waistcirc< 88.4 31  960.53810 22.55645  
     4) hipcirc< 96.25 14  222.26480 18.41143  
       8) age< 60.5 9   66.88096 16.19222 *
       9) age>=60.5 5   31.27692 22.40600 *
     5) hipcirc>=96.25 17  299.64700 25.97000  
      10) waistcirc< 77.75 6   30.73455 22.32500 *
      11) waistcirc>=77.75 11  145.71480 27.95818 *
   3) waistcirc>=88.4 25 1417.11400 41.34880  
     6) waistcirc< 104.75 18  330.57920 38.09111  
      12) hipcirc< 109.9 9   68.99962 34.37556 *
      13) hipcirc>=109.9 9   13.08320 41.80667 *
     7) waistcirc>=104.75 7  404.30040 49.72571 *
> plot(bodyfat_prune)
> text(bodyfat_prune, use.n=T)
> # 
は、決定ツリーモデルを用いて予測し、実際の値と比較する.図中のabline()は対角線を描いている.良い予測モデルでは、ほとんどの点が対角線に落ちるか、対角線に近づくほど良い.
> DEXfat_pred  xlim  plot(DEXfat_pred ~ DEXfat, data=bodyfat.test, xlab="Observed",
+ ylab="Predicted", ylim=xlim, xlim=xlim)
> abline(a=0, b=1)
> # 

3.ランダム森林
irisデータセットを例に挙げます.
randomForest()を使用すると、2つの制限があります.1つ目は、この関数が欠落した値を持つデータを処理できず、欠落した値を事前に処理することです.2つ目は,分類属性の水平分割数の最大値が32であり,32より大きい分類属性は事前に変換する必要がある.
もう1つはpartyパケットのcforest()を使用し、分類属性の水平分割数を限定しない.
トレーニングセットとテストセットの区分:
> ind  trainData  testData 
訓練ランダム森林モデル:
> library(randomForest)
> rf  table(predict(rf), trainData$Species)
            
             setosa versicolor virginica
  setosa         36          0         0
  versicolor      0         31         1
  virginica       0          1        35
> print(rf)

Call:
 randomForest(formula = Species ~ ., data = trainData, ntree = 100,      proximity = TRUE) 
               Type of random forest: classification
                     Number of trees: 100
No. of variables tried at each split: 2

        OOB estimate of  error rate: 1.92%
Confusion matrix:
           setosa versicolor virginica class.error
setosa         36          0         0  0.00000000
versicolor      0         31         1  0.03125000
virginica       0          1        35  0.02777778
> attributes(rf)
$names
 [1] "call"            "type"            "predicted"       "err.rate"       
 [5] "confusion"       "votes"           "oob.times"       "classes"        
 [9] "importance"      "importanceSD"    "localImportance" "proximity"      
[13] "ntree"           "mtry"            "forest"          "y"              
[17] "test"            "inbag"           "terms"          

$class
[1] "randomForest.formula" "randomForest"   
は、生成されたランダムな森の異なる木に基づいて誤差率を描画する.
> plot(rf)
> # 
変数の重要度を表示します.
> importance(rf)
             MeanDecreaseGini
Sepal.Length         6.485090
Sepal.Width          1.380624
Petal.Length        32.498074
Petal.Width         28.250058
> varImpPlot(rf)
> # 
は最後にテストセットを使用してテストを行い、table()とmargin()で結果を表示します.図中のデータ点の余白は、正確に分類された割合から、他のカテゴリに分類された最大割合を減算する.一般に、マージンが正数であることは、データポイントの分割が正しいことを示します.
> irisPred  table(irisPred, testData$Species)
            
irisPred     setosa versicolor virginica
  setosa         14          0         0
  versicolor      0         17         3
  virginica       0          1        11
> plot(margin(rf, testData$Species))
> #