1. 程式人生 > >R語言之決策樹和隨機森林

R語言之決策樹和隨機森林

總結決策樹之前先總結一下特徵的生成和選擇,因為決策樹就是一種內嵌型的特徵選擇過程,它的特徵選擇和演算法是融合在一起的,不需要額外的特徵選擇。

一、特徵生成:

特徵生成是指在收集資料之時原始資料就具有的資料特徵,這些資料特徵由收集的資料決定(其實也就是在產品定型時設定的需要收集的資料特徵),當然,在資料預處理時,也可以在此基礎上構造一些新的資料特徵,這些特徵越多越好,表示你考慮問題比較周全,具體那些變數有用或沒用,這要交給下一步特徵選擇來決定。

二、特徵選擇

特徵選擇是指在原有資料特徵的基礎上,去除重要性比較低的特徵變數,過濾出有用的特徵變數。這裡比較困難的是搞清楚什麼樣的特徵比較重要?這需要根據具體的問題具體分析,有些變數的選擇可以很直觀的看出來,但這種直覺也不一定正確。對於常用特徵選擇方法主要有:過濾型、包裝型、內嵌型。

過濾型:是指你可以根據某個統計量的大小排序來選擇特徵變數,如相關係數、p值、R值等

包裝型:是指在一個特徵集合中選取最優的特徵子集。具體需要考慮:用什麼樣的演算法來選取?選取的最優的標準是什麼?

常用的演算法是分步迴歸包括向前搜尋、向後刪除、雙向搜尋

向前搜尋:每次選取一個能使模型預測或分類效果最好的特徵變數進來,進來後不退出,直到模型改善效果不再明顯;

向後刪除:是指每次從特徵全集中每次刪除一個特徵變數能使模型預測或分類效果最好,退出後不進來,直到模型改善效果不再明顯;

雙向搜尋:是指每次每次刪除一個特徵變數或加入一個特徵變數能使模型預測或分類效果最好,退出的不進來,進來的不退出,直到模型改善效果不再明顯;

這裡再提一下特徵變數選擇的幾個標準:p值、R值、AIC(越小效果越好)、BIC(越小效果越好)、熵(越小效果越好)

內嵌型:這裡應該主要就是像決策樹這樣的情況,演算法內部完成特徵變數的選取。

三、決策樹

決策的幾個要點:1、如何決策?(也就是如何樹如何分叉)------熵和資訊增益---這裡麵包含的就是特徵的選擇?哪個特徵變數包含的資訊量大,就排在前面,至於最後樹的深度就決定特徵變數的個數。

當然不同的演算法使用的衡量的標準不同,還有:資訊增益比、基尼不純係數

2、如何剪枝?-----一般是事後剪枝

3、連續性變數如何離散化?-----閾值的選擇

熵:是指資訊的混合程度(混亂程度),熵【0-1】越大表示該集合中混合的資訊越多,也就表明這次的分叉效果不好還是有很多不同類的資訊混在一起

資訊增益:熵值的減少量,越大越好

決策樹模型特點:模型易於解釋;儲存空間較小,以樹的形式儲存,決策樹是一個弱分類器,不能完全分類,需要把多個弱分類器通過多數投票法組合在一起。

四、R包實現決策樹

library(rpart)

library(rpart.plot)

## rpart.control對樹進行一些設定

## xval是10折交叉驗證
## minsplit是最小分支節點數,這裡指大於等於20,那麼該節點會繼續分劃下去,否則停止
## minbucket:葉子節點最小樣本數
## maxdepth:樹的深度
## cp全稱為complexity parameter,指某個點的複雜度,對每一步拆分,模型的擬合優度必須提高的程度
ct <- rpart.control(xval=10, minsplit=20, cp=0.1)
## kyphosis是rpart這個包自帶的資料集
## na.action:缺失資料的處理辦法,預設為刪除因變數缺失的觀測而保留自變數缺失的觀測。         
## method:樹的末端資料型別選擇相應的變數分割方法:
## 連續性method=“anova”,離散型method=“class”,計數型method=“poisson”,生存分析型method=“exp”
## parms用來設定三個引數:先驗概率、損失矩陣、分類純度的度量方法(gini和information)
## cost是損失矩陣,在剪枝的時候,葉子節點的加權誤差與父節點的誤差進行比較,考慮損失矩陣的時候,從將“減少-誤差”調整為“減少-損失”
data("Kyphosis")
fit <- rpart(Kyphosis~Age + Number + Start,data=kyphosis, method="class",control=ct,parms = list(prior = c(0.65,0.35), split = "information"));
## 作圖有2種方法
## 第一種:
par(mfrow=c(1,3));plot(fit); text(fit,use.n=T,all=T,cex=0.9)
## 第二種,這種會更漂亮一些:
rpart.plot(fit, branch=1, branch.type=2, type=1, extra=102,
           shadow.col="gray", box.col="green",
           border.col="blue", split.col="red",
           split.cex=1.2, main="Kyphosis決策樹");

## rpart包提供了複雜度損失修剪的修剪方法,printcp會告訴分裂到每一層,cp是多少,平均相對誤差是多少
## 交叉驗證的估計誤差(“xerror”列),以及標準誤差(“xstd”列),平均相對誤差=xerror±xstd
printcp(fit)
## 通過上面的分析來確定cp的值
##呼叫CP(complexity parameter)與xerror的相關圖,一種方法是尋找最小xerror點所對應
#的CP值,並由此CP值決定樹的大小,另一種方法是利用1SE方法,尋找xerror+SE的最小點對應的CP值。
plotcp(fit)
##利用以下方法進行修剪:
## prune(fit, cp= fit$cptable[which.min(fit$cptable[,"xerror"]),"CP"])
fit2 <- prune(fit, cp=0.01)

#利用模型預測
ndata=data.frame(...) 
predict(fit,newdata=ndata) 

#案例
str(iris)
set.seed(1234)#設定隨機數種子--使每次執行時產生的一組隨機數相同,便於結果的重現
#抽樣:從iris資料集中隨機抽70%定義為訓練資料集,30%為測試資料集(常用)
#這裡是對行抽樣,ind是一個只含1和2的向量
ind <- sample(2, nrow(iris), replace=TRUE, prob=c(0.7, 0.3))
trainData <- iris[ind==1,]
testData <- iris[ind==2,]
f<-Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width

#訓練資料
fit<-rpart(f,trainData)

#預測

re<-predict(fit,testData)

#******************或者用其他包********************
library(party)
#建立決策樹模型預測花的種類
myFormula <- Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width
iris_ctree <- ctree(myFormula, data=trainData)
# 檢視預測的結果
z<-table(predict(iris_ctree), trainData$Species)
#可以根據以上列聯表求出預測的正確率---評估模型

#計算準確度

q<-sum(diag(z))/sum(z)

五、機器整合與隨機森林法則

前面說過,決策樹的一個特點是:弱分類器,分類不完全,需要利用整合投票的方式來增加精確度和穩健性。

機器整合演算法:對於資料集訓練多個模型,對於分類問題,可以採用投票的方法,選擇票數最多的類別作為最終的類別,而對於迴歸問題,可以採用取均值的方法,取得的均值作為最終的結果。主要的整合演算法有bagging和adaboost演算法。

隨機森林:隨機森林就是利用機器整合多個決策樹,主要有兩個引數,一個是決策樹的個數,一個是每棵樹的特徵變數個數。

隨機森林特點:精確度高、穩健性好,但可解釋性差。(可以知道各個變數的重要性)

R包實現機器整合演算法:

#adabag包均有函式實現bagging和adaboost的分類建模
#利用全部資料建模
library(adabag)
a<-boosting(Species~.,data=iris)
z0<-table(iris[,5],predict(a,iris)$class)
#計算誤差率
E0<-(sum(z0)-sum(diag(z0)))/sum(z0)
barplot(a$importance)
b<-errorevol(a,iris)#計算全體的誤差演變
plot(b$error,type="l",main="AdaBoost error vs number of trees") #對誤差演變進行畫圖


a<-bagging(Species~.,data=iris)
z0<-table(iris[,5],predict(a,iris)$class)
#計算誤差率
E0<-(sum(z0)-sum(diag(z0)))/sum(z0)
barplot(a$importance)
b<-errorevol(a,iris)#計算全體的誤差演變
plot(b$error,type="l",main="AdaBoost error vs number of trees") #對誤差演變進行畫圖


#5折交叉驗證
set.seed(1044)  #設定隨機種子
samp=c(sample(1:50,25),sample(51:100,25),sample(101:150,25)) #進行隨機抽樣
a=boosting(Species~.,data=iris[samp,]) #利用訓練集建立adaboost分類模
z0<-table(iris[samp,5],predict(a,iris[samp,])$class)#訓練集結果
z1<-table(iris[-samp,5],predict(a,iris[-samp,])$class)#測試集結果
E0<-(sum(z0)-sum(diag(z0)))/sum(z0)
E1<-(sum(z0)-sum(diag(z0)))/sum(z1)

a=bagging(Species~.,data=iris[samp,]) #利用訓練集建立adaboost分類模
z0<-table(iris[samp,5],predict(a,iris[samp,])$class)#訓練集結果
z1<-table(iris[-samp,5],predict(a,iris[-samp,])$class)#測試集結果
E0<-(sum(z0)-sum(diag(z0)))/sum(z0)
E1<-(sum(z0)-sum(diag(z0)))/sum(z1)

R包實現隨機森林:

#隨機森林法則
library(randomForest)
library(foreign)
data("iris")

#抽樣資料
ind<-sample(2,nrow(iris),replace = TRUE,prob=c(0.7,0.3))
traning<-iris[ind==1,]
testing<-iris[ind==2,]

#訓練資料
rf <- randomForest(Species ~ ., data=traning, ntree=100, proximity=TRUE)

#預測
table(predict(rf),traning$Species)
table(predict(rf,testing),testing$Species)

#檢視預測的效果
print(rf)
plot(rf)

#檢視重要性
importance(rf)
varImpPlot(rf)