關注微信號:小程在線
關注CSDN博客:程志偉的博客
R版本:3.4.4
最新的R官網取消了mvpart包,有需要的可以留言或者加微信,我用R3.6.1版本的顯示這個包不能使用。
還需要安裝java環境,下載jdk,配置環境變量。
draw.tree函數:繪製樹狀圖
J48函數:實現C4.5算法
maptree包:提供draw.tree函數
mvpart包:提供數據集car.test.frame
post函數:對rpart()結果繪製演示圖
prune.rpart():對rpart()的結果進行剪枝
rpart包:提供函數rpart()、prune.rpart()、post()
rpart.plot包提供rpart.plot函數,繪製決策時
RWeka包:提供函數J48
sampling包:strata函數用於分層抽樣
#設置工作路徑
> setwd('G:\\R語言\\大三下半年\\數據挖掘:R語言實戰\\')
Warning message:
file ‘.RData’ has magic number 'RDX3'
Use of save versions prior to 2 is deprecated
> library(mvpart)
> data("car.test.frame")
> head(car.test.frame)
Price Country Reliability Mileage Type Weight Disp. HP
Eagle Summit 4 8895 USA 4 33 Small 2560 97 113
Ford Escort 4 7402 USA 2 33 Small 2345 114 90
Ford Festiva 4 6319 Korea 4 37 Small 1845 81 63
Honda Civic 4 6635 Japan/USA 5 32 Small 2260 91 92
Mazda Protege 4 6599 Japan 5 32 Small 2440 113 103
Mercury Tracer 4 8672 Mexico 4 26 Small 2285 97 82
> car.test.frame$Mileage <- 100*4.546/(1.6*car.test.frame$Mileage)
> names(car.test.frame) <- c("價格","產地","可靠性","油耗","類型","車重","發動機功率","淨馬力")
> head(car.test.frame)
價格 產地 可靠性 油耗 類型 車重 發動機功率 淨馬力
Eagle Summit 4 8895 USA 4 8.609848 Small 2560 97 113
Ford Escort 4 7402 USA 2 8.609848 Small 2345 114 90
Ford Festiva 4 6319 Korea 4 7.679054 Small 1845 81 63
Honda Civic 4 6635 Japan/USA 5 8.878906 Small 2260 91 92
Mazda Protege 4 6599 Japan 5 8.878906 Small 2440 113 103
Mercury Tracer 4 8672 Mexico 4 10.927885 Small 2285 97 82
#str()函數顯示該數據集有60行8列
> str(car.test.frame)
'data.frame': 60 obs. of 8 variables:
$ 價格 : int 8895 7402 6319 6635 6599 8672 7399 7254 9599 5866 ...
$ 產地 : Factor w/ 8 levels "France","Germany",..: 8 8 5 4 3 6 4 5 3 3 ...
$ 可靠性 : int 4 2 4 5 5 4 5 1 5 NA ...
$ 油耗 : num 8.61 8.61 7.68 8.88 8.88 ...
$ 類型 : Factor w/ 6 levels "Compact","Large",..: 4 4 4 4 4 4 4 4 4 4 ...
$ 車重 : int 2560 2345 1845 2260 2440 2285 2275 2350 2295 1900 ...
$ 發動機功率: int 97 114 81 91 113 97 97 98 109 73 ...
$ 淨馬力 : int 113 90 63 92 103 82 90 74 90 73 ...
> summary(car.test.frame)
價格 產地 可靠性 油耗 類型
Min. : 5866 USA :26 Min. :1.000 Min. : 7.679 Compact:15
1st Qu.: 9932 Japan :19 1st Qu.:2.000 1st Qu.:10.523 Large : 3
Median :12216 Japan/USA: 7 Median :3.000 Median :12.353 Medium :13
Mean :12616 Korea : 3 Mean :3.388 Mean :11.962 Small :13
3rd Qu.:14933 Germany : 2 3rd Qu.:5.000 3rd Qu.:13.530 Sporty : 9
Max. :24760 France : 1 Max. :5.000 Max. :15.785 Van : 7
(Other) : 2 NA's :11
車重 發動機功率 淨馬力
Min. :1845 Min. : 73.0 Min. : 63.0
1st Qu.:2571 1st Qu.:113.8 1st Qu.:101.5
Median :2885 Median :144.5 Median :111.5
Mean :2901 Mean :152.1 Mean :122.3
3rd Qu.:3231 3rd Qu.:180.0 3rd Qu.:142.8
Max. :3855 Max. :305.0 Max. :225.0
> #2. 數據預處理
> #下面我們着重看油耗變量,因爲在以下的建模過程中,將以油耗作爲目標變量
> #一個數據集來分別構建出以離散型和連續型變量爲各自目標變量的分類樹和迴歸樹,考慮添加一列變量——分組油耗,即將油耗變量劃分爲三個組別,A:11.6~15.8個油、B:9~11.6個油、C:7.7~9個油,成爲含有3個水平的A、B、C的因子變量。
> Group_Mileage=matrix(0,60,1) #設矩陣Group_Mileage用於存放新變量
> Group_Mileage[which(car.test.frame$"油耗">=11.6)]="A"
> Group_Mileage[which(car.test.frame$"油耗"<=9)]="C" #將油耗在7.7~9區間的樣本Group_Mileage值取C
> Group_Mileage[which(Group_Mileage==0)]="B" #將油耗不在組A、C的樣本Group_Mileage值取B
> car.test.frame$"分組油耗"=Group_Mileage #在數據集中添加新變量分組油耗
> car.test.frame[1:10,c(4,9)]
油耗 分組油耗
Eagle Summit 4 8.609848 C
Ford Escort 4 8.609848 C
Ford Festiva 4 7.679054 C
Honda Civic 4 8.878906 C
Mazda Protege 4 8.878906 C
Mercury Tracer 4 10.927885 B
Nissan Sentra 4 8.609848 C
Pontiac LeMans 4 10.147321 B
Subaru Loyale 4 11.365000 B
Subaru Justy 3 8.356618 C
> a=round(1/4*sum(car.test.frame$"分組油耗"=="A"))
> b=round(1/4*sum(car.test.frame$"分組油耗"=="B"))
> c=round(1/4*sum(car.test.frame$"分組油耗"=="C"))
> #分別計算A、B、C組中應抽取測試集樣本數,記爲a、b、c
> a;b;c
[1] 9
[1] 4
[1] 2
#使用strata()函數對car.test.frame中的“分組油耗”變量進行分層抽樣
> library(sampling)
> sub=strata(car.test.frame, stratanames="分組油耗", size=c(c,b,a), method="srswor")
> sub
分組油耗 ID_unit Prob Stratum
4 C 4 0.2222222 1
7 C 7 0.2222222 1
6 B 6 0.2500000 2
8 B 8 0.2500000 2
17 B 17 0.2500000 2
21 B 21 0.2500000 2
20 A 20 0.2571429 3
38 A 38 0.2571429 3
42 A 42 0.2571429 3
47 A 47 0.2571429 3
51 A 51 0.2571429 3
52 A 52 0.2571429 3
56 A 56 0.2571429 3
57 A 57 0.2571429 3
60 A 60 0.2571429 3
> Train_Car=car.test.frame[-sub$ID_unit,] #生成訓練集
> Test_Car=car.test.frame[sub$ID_unit,] #生成測試集
> nrow(Train_Car);nrow(Test_Car) #顯示訓練集、測試集行數
[1] 45
[1] 15
> ##################應用案例##################
> library('rpart')
載入程輯包:‘rpart’
The following object is masked _by_ ‘.GlobalEnv’:
car.test.frame
The following objects are masked from ‘package:mvpart’:
meanvar, na.rpart, path.rpart, plotcp, post, printcp, prune, prune.rpart,
rpart, rpart.control, rsq.rpart, snip.rpart, xpred.rpart
> #1. 對油耗變量建立迴歸樹——數字結果
#按照公式對訓練集構建迴歸樹method="anova"
> formula_Car_Reg=油耗~價格+產地+可靠性+類型+車重+發動機功率+淨馬力 #設定模型公式
> rp_Car_Reg=rpart(formula_Car_Reg,Train_Car,method="anova")
> print(rp_Car_Reg) #導出迴歸樹基本信息
n= 45
node), split, n, deviance, yval
* denotes terminal node
1) root 45 186.172800 11.845280
2) 發動機功率< 134 19 32.628130 9.977205 *
3) 發動機功率>=134 26 38.786870 13.210420
6) 價格< 11522 7 3.003835 11.877100 *
7) 價格>=11522 19 18.754370 13.701630 *
#按照節點層次以不同縮進量列出,並在每條節點信息後以星號*標示出是否爲葉節點。
> printcp(rp_Car_Reg) #導出迴歸樹的cp表格
Regression tree:
rpart(formula = formula_Car_Reg, data = Train_Car, method = "anova")
Variables actually used in tree construction:
[1] 發動機功率 價格
Root node error: 186.17/45 = 4.1372
n= 45
CP nsplit rel error xerror xstd
1 0.616405 0 1.00000 1.04401 0.182755
2 0.091467 1 0.38360 0.46353 0.075249
3 0.010000 2 0.29213 0.42704 0.063786
#獲取決策樹rp_Car_Reg詳細信息,Variable importance變量的最要程度、improve對分支的提升程度
> summary(rp_Car_Reg)
Call:
rpart(formula = formula_Car_Reg, data = Train_Car, method = "anova")
n= 45
CP nsplit rel error xerror xstd
1 0.61640483 0 1.0000000 1.0440087 0.18275540
2 0.09146694 1 0.3835952 0.4635295 0.07524941
3 0.01000000 2 0.2921282 0.4270404 0.06378585
Variable importance
發動機功率 車重 價格 淨馬力 類型 產地
26 20 14 14 13 12
Node number 1: 45 observations, complexity param=0.6164048
mean=11.84528, MSE=4.137174
left son=2 (19 obs) right son=3 (26 obs)
Primary splits:
發動機功率 < 134 to the left, improve=0.6164048, (0 missing)
價格 < 9446.5 to the left, improve=0.5563919, (0 missing)
車重 < 2567.5 to the left, improve=0.5509927, (0 missing)
類型 splits as RRRLRR, improve=0.4392540, (0 missing)
淨馬力 < 109 to the left, improve=0.3982844, (0 missing)
Surrogate splits:
車重 < 2747.5 to the left, agree=0.889, adj=0.737, (0 split)
淨馬力 < 109 to the left, agree=0.800, adj=0.526, (0 split)
類型 splits as RRRLRR, agree=0.778, adj=0.474, (0 split)
價格 < 9446.5 to the left, agree=0.756, adj=0.421, (0 split)
產地 splits as LLLLR-RR, agree=0.756, adj=0.421, (0 split)
Node number 2: 19 observations
mean=9.977205, MSE=1.71727
Node number 3: 26 observations, complexity param=0.09146694
mean=13.21042, MSE=1.491803
left son=6 (7 obs) right son=7 (19 obs)
Primary splits:
價格 < 11522 to the left, improve=0.4390315, (0 missing)
車重 < 3087.5 to the left, improve=0.3622234, (0 missing)
類型 splits as LRL-RR, improve=0.3121080, (0 missing)
發動機功率 < 185.5 to the left, improve=0.1511378, (0 missing)
淨馬力 < 148.5 to the left, improve=0.1511378, (0 missing)
Surrogate splits:
車重 < 2757.5 to the left, agree=0.846, adj=0.429, (0 split)
產地 splits as --RLL-RR, agree=0.808, adj=0.286, (0 split)
類型 splits as LRR-RR, agree=0.808, adj=0.286, (0 split)
淨馬力 < 103.5 to the left, agree=0.808, adj=0.286, (0 split)
發動機功率 < 142 to the left, agree=0.769, adj=0.143, (0 split)
Node number 6: 7 observations
mean=11.8771, MSE=0.4291194
Node number 7: 19 observations
mean=13.70163, MSE=0.9870723
> #下面我們嘗試改變rpart()函數的若干參數值,minsplit=10,將分支包含最小樣本數minsplit從默認值20改爲10,新的迴歸樹記爲rp_Car_Reg1。
> rp_Car_Reg1=rpart(formula_Car_Reg,Train_Car,method="anova",minsplit=10)
> print(rp_Car_Reg1) #導出迴歸樹基本信息
n= 45
node), split, n, deviance, yval
* denotes terminal node
1) root 45 186.172800 11.845280
2) 發動機功率< 134 19 32.628130 9.977205
4) 價格< 9504.5 8 2.649246 8.582424 *
5) 價格>=9504.5 11 3.096802 10.991590 *
3) 發動機功率>=134 26 38.786870 13.210420
6) 價格< 11522 7 3.003835 11.877100 *
7) 價格>=11522 19 18.754370 13.701630
14) 類型=Compact,Medium 12 2.880021 13.081890 *
15) 類型=Large,Sporty,Van 7 3.364168 14.764060 *
> printcp(rp_Car_Reg1) #導出迴歸樹的cp表格
Regression tree:
rpart(formula = formula_Car_Reg, data = Train_Car, method = "anova",
minsplit = 10)
Variables actually used in tree construction:
[1] 發動機功率 價格 類型
Root node error: 186.17/45 = 4.1372
n= 45
CP nsplit rel error xerror xstd
1 0.616405 0 1.000000 1.04535 0.183175
2 0.144393 1 0.383595 0.46279 0.074342
3 0.091467 2 0.239202 0.36798 0.080715
4 0.067197 3 0.147735 0.38852 0.111059
5 0.010000 4 0.080538 0.32070 0.111356
#cp值表示可以使模型擬合程度提高的節點,剪去不重要的分支
> rp_Car_Reg2=rpart(formula_Car_Reg,Train_Car,method="anova",cp=0.1)
> #將CP值從默認的0.01改爲0.1,新的迴歸樹記爲rp_Car_Reg2
> print(rp_Car_Reg2) #導出迴歸樹基本信息
n= 45
node), split, n, deviance, yval
* denotes terminal node
1) root 45 186.17280 11.845280
2) 發動機功率< 134 19 32.62813 9.977205 *
3) 發動機功率>=134 26 38.78687 13.210420 *
> printcp(rp_Car_Reg2) #導出迴歸樹的cp表格
Regression tree:
rpart(formula = formula_Car_Reg, data = Train_Car, method = "anova",
cp = 0.1)
Variables actually used in tree construction:
[1] 發動機功率
Root node error: 186.17/45 = 4.1372
n= 45
CP nsplit rel error xerror xstd
1 0.6164 0 1.0000 1.07992 0.189818
2 0.1000 1 0.3836 0.47707 0.078252
> #剪枝函數也可以實現同樣的效果
> rp_Car_Reg3=prune.rpart(rp_Car_Reg,cp=0.1)
> print(rp_Car_Reg3)
n= 45
node), split, n, deviance, yval
* denotes terminal node
1) root 45 186.17280 11.845280
2) 發動機功率< 134 19 32.62813 9.977205 *
3) 發動機功率>=134 26 38.78687 13.210420 *
> printcp(rp_Car_Reg3)
Regression tree:
rpart(formula = formula_Car_Reg, data = Train_Car, method = "anova")
Variables actually used in tree construction:
[1] 發動機功率
Root node error: 186.17/45 = 4.1372
n= 45
CP nsplit rel error xerror xstd
1 0.6164 0 1.0000 1.04401 0.182755
2 0.1000 1 0.3836 0.46353 0.075249
> #對所生成樹的大小也可以通過深度函數maxdepth來控制
> rp_Car_Reg4=rpart(formula_Car_Reg,Train_Car,method="anova",maxdepth=1)
> print(rp_Car_Reg4)
n= 45
node), split, n, deviance, yval
* denotes terminal node
1) root 45 186.17280 11.845280
2) 發動機功率< 134 19 32.62813 9.977205 *
3) 發動機功率>=134 26 38.78687 13.210420 *
> printcp(rp_Car_Reg4)
Regression tree:
rpart(formula = formula_Car_Reg, data = Train_Car, method = "anova",
maxdepth = 1)
Variables actually used in tree construction:
[1] 發動機功率
Root node error: 186.17/45 = 4.1372
n= 45
CP nsplit rel error xerror xstd
1 0.6164 0 1.0000 1.09740 0.191557
2 0.0100 1 0.3836 0.52651 0.084732
#2. 對油耗變量建立迴歸樹——樹形結果
> rp_Car_Plot=rpart(formula_Car_Reg,Train_Car,method="anova",minsplit=10)
> #設置minsplit爲10,新的迴歸樹記爲rp_Car_Plot
> print(rp_Car_Plot)
n= 45
node), split, n, deviance, yval
* denotes terminal node
1) root 45 186.172800 11.845280
2) 發動機功率< 134 19 32.628130 9.977205
4) 價格< 9504.5 8 2.649246 8.582424 *
5) 價格>=9504.5 11 3.096802 10.991590 *
3) 發動機功率>=134 26 38.786870 13.210420
6) 價格< 11522 7 3.003835 11.877100 *
7) 價格>=11522 19 18.754370 13.701630
14) 類型=Compact,Medium 12 2.880021 13.081890 *
15) 類型=Large,Sporty,Van 7 3.364168 14.764060 *
> library(rpart.plot)
> rpart.plot(rp_Car_Plot) #繪製決策樹
> #相比於數字結果,從樹狀圖中我們可以更清晰的看到模型對於目標變量的預測過程
> rpart.plot(rp_Car_Plot,type=4) #更改type參數爲類型4,繪製決策樹
> #每一分支的取值範圍也被標示出來,而且在每個節點的油耗的預測值也被標出
> #當樹的分支較多時,我們還可以選擇設置“分支”參數branch=1來獲得垂直枝幹形狀的決策
> #樹以減少圖形所佔空間,使得樹狀圖的枝幹不再顯得雜亂無章,更方便查看和分析。
> rpart.plot(rp_Car_Plot,type=4,branch=1)
> #參數fallen.leaves設置爲TRUE,即表示將所有葉節點一致的擺放在樹的最下端
> rpart.plot(rp_Car_Plot,type=4,branch=1,fallen.leaves=TRUE)
> library(maptree)
載入需要的程輯包:cluster
> draw.tree(rp_Car_Plot, col=rep(1,8), nodeinfo=TRUE)#利用draw.tree()繪製決策樹
> plot(rp_Car_Plot,uniform=TRUE,main="plot: Regression TRUE")
> text(rp_Car_Plot,use.n=TRUE,all=TRUE)#用plot()直接繪圖,並在圖中添加相關文字信息
> post(rp_Car_Plot,file="") #用post()函數繪製決策樹
> #3. 對分組油耗變量建立分類樹
> formula_Car_Cla=分組油耗~價格+產地+可靠性+類型+車重+發動機功率+淨馬力
> rp_Car_Cla=rpart(formula_Car_Cla, Train_Car, method="class", minsplit=5)
> #按公式formula_Car_Cla對訓練集創建分類樹
> print(rp_Car_Cla)
n= 45
node), split, n, loss, yval, (yprob)
* denotes terminal node
1) root 45 19 A (0.57777778 0.26666667 0.15555556)
2) 發動機功率>=134 26 2 A (0.92307692 0.07692308 0.00000000)
4) 價格>=11222 20 0 A (1.00000000 0.00000000 0.00000000) *
5) 價格< 11222 6 2 A (0.66666667 0.33333333 0.00000000)
10) 發動機功率< 152 4 0 A (1.00000000 0.00000000 0.00000000) *
11) 發動機功率>=152 2 0 B (0.00000000 1.00000000 0.00000000) *
3) 發動機功率< 134 19 9 B (0.10526316 0.52631579 0.36842105)
6) 價格>=9504.5 11 2 B (0.18181818 0.81818182 0.00000000) *
7) 價格< 9504.5 8 1 C (0.00000000 0.12500000 0.87500000) *
> #以上輸出結果與迴歸樹類似,不同之處僅在於每個節點的預測值不再是具體數值,而是A、B、C,即分組油耗的三個取值水平。
> rpart.plot(rp_Car_Cla, type=4, fallen.leaves=TRUE) #對rp_Car_Cla繪製分類樹
#發動機高於134的且價格高於1萬美元的車,屬於A類,高油耗;最左邊的分支,反之屬於C類,最右側分支。
#4. 對測試集Test_Car預測目標變量
> pre_Car_Cla=predict(rp_Car_Cla,Test_Car,type="class")
> #對測試集Test_Car中觀測樣本中的分組油耗指標進行預測
> pre_Car_Cla #顯示預測結果
Honda Civic 4 Nissan Sentra 4 Mercury Tracer 4 Pontiac LeMans 4
C C C C
Ford Probe Plymouth Laser Nissan 240SX 4 Acura Legend V6
B B A A
Eagle Premier V6 Nissan Maxima V6 Buick Le Sabre V6 Chevrolet Caprice V8
A A A A
Ford Aerostar V6 Mazda MPV V6 Nissan Van 4
A A A
Levels: A B C
> (p=sum(as.numeric(pre_Car_Cla!=Test_Car$"分組油耗"))/nrow(Test_Car)) #計算錯誤率
[1] 0.1333333
> table(Test_Car$"分組油耗", pre_Car_Cla) #獲取混淆矩陣
pre_Car_Cla
A B C
A 9 0 0
B 0 2 2
C 0 0 2
######################## C4.5應用 ###################
> #C4.5算法僅適用離散變量,即構建分類樹,因此這裏我們就繼續沿用上面的數據集來對分組油
> #耗指標進行建樹。需要說明的是,用於實現C4.5算法的核心函數J48()對中文識別不太完善,因此我們將使用原
> #英文數據集中的變量名稱。#“價格(Price)”、產地(Country)、可靠性(Reliability)、英里數(Mileage)、類型(Type)、
> #車重(Weight)、發動機功率(Disp.),以及淨馬力(HP),分組油耗(Oil_Consumption)。
> #install.packages("rJava")
> library(RWeka)
> names(Train_Car)=c("Price","Country","Reliability","Mileage","Type","Weight","Disp.",
+ "HP","Oil_Consumption") #更改爲英文變量名
> Train_Car$Oil_Consumption=as.factor(Train_Car$Oil_Consumption)
> #將分組喲好的變量類型改爲因子型,使J48()函數可識別
> formula=Oil_Consumption~Price+Country+Reliability+Type+Weight+Disp.+HP
> C45_0=J48(formula,Train_Car) #在默認參數去之下,構建分類樹模型C45_0
> C45_0
J48 pruned tree
------------------
Price <= 9410: C (7.0/1.0)
Price > 9410
| Disp. <= 132: B (6.0)
| Disp. > 132
| | Price <= 10989
| | | Reliability <= 1: B (2.0)
| | | Reliability > 1: A (4.0/1.0)
| | Price > 10989: A (17.0)
Number of Leaves : 5
Size of the tree : 9
> #共計10個葉節點,15個節點,最後括號中的數字表示有多少觀測樣本被歸入該分支,且其中有
> #幾個是被錯分的。
> summary(C45_0)
=== Summary ===
Correctly Classified Instances 34 94.4444 %
Incorrectly Classified Instances 2 5.5556 %
Kappa statistic 0.9045
Mean absolute error 0.0595
Root mean squared error 0.1725
Relative absolute error 15.067 %
Root relative squared error 39.0042 %
Total Number of Instances 36
=== Confusion Matrix ===
a b c <-- classified as
20 0 0 | a = A
1 8 1 | b = B
0 0 6 | c = C
> #下面我們通過control參數控制分類樹的生成過程。參數M,即對每個葉節點設置最小觀測樣本
> #量來對樹進行剪枝。我們知道,M的默認值爲2,現在將其取值爲3來減去若干所含樣本量較小
> #的分支。
> C45_1=J48(formula,Train_Car,control=Weka_control(M=3))
> #取control參數的M值爲3,構建分類樹模型C45_1
> C45_1
J48 pruned tree
------------------
Price <= 9410: C (7.0/1.0)
Price > 9410
| Disp. <= 132: B (6.0)
| Disp. > 132: A (23.0/3.0)
Number of Leaves : 3
Size of the tree : 5
> plot(C45_1) #對C45_1繪製分類樹