決策樹實現(R)

###### decision tree ##########
install.packages('rpart.plot')
install.packages('rattle')
install.packages('RColorBrewer')

library(rpart)
library(rattle)
library(rpart.plot)
library(RColorBrewer)

###### model #############

model <- rpart(Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, data = iris,  method="class")

plot(model)
text(model)
fancyRpartPlot(model)
Prediction <- predict(model, test, type = "class")

model1 <- rpart(Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, data = iris,  method="class",control=rpart.control(minsplit=2, cp=0))
fancyRpartPlot(model1)

###### C5.0 #############
install.packages('C50')
select<-sample(1:nrow(iris),length(iris)*0.7)
train=iris[-select,]
test=iris[select,]

train<-na.omit(train)
library(C50)
ls('package:C50')
tc<-C5.0Control(subset =F,CF=0.25,winnow=F,noGlobalPruning=F,minCases =20)
model2 <- C5.0(Species ~.,data=train,rules=F,control =tc)
summary( model2 )

plot(model2)
C5imp(model2)


#自己編######## 
#決策樹的R語言實現如下:

library(plyr)

# 測試數據集 http://archive.ics.uci.edu/ml/datasets/Car+Evaluation

##計算訓練集合D的熵H(D)
##輸入:trainData 訓練集,類型爲數據框
##      nClass 指明訓練集中第nClass列爲分類結果
##輸出:訓練集的熵
cal_HD <- function(trainData, nClass){
  if ( !(is.data.frame(trainData) & is.numeric(nClass)) )
    "input error"
  if (length(trainData) < nClass)
    "nClass is larger than the length of trainData"

  rownum <- nrow(trainData)
  #對第nClass列的值統計頻數
  calss.freq <- count(trainData,nClass) 

  #計算每個取值的  概率*log2(概率)
  calss.freq <- mutate(calss.freq, freq2 = (freq / rownum)*log2(freq / rownum))

  -sum(calss.freq[,"freq2"])

  #使用arrange代替order,方便的按照多列對數據框進行排序 
  #mtcars.new2 <- arrange(mtcars, cyl, vs, gear) 
}

#cal_HD(mtcars,11)

##計算訓練集合D對特徵值A的條件熵H(D|A)
##輸入:trainData 訓練集,類型爲數據框
##      nClass 指明訓練集中第nClass列爲分類結果
##      nA 指明trainData中條件A的列號
##輸出:訓練集trainData對特徵A的條件熵
cal_HDA <- function(trainData, nClass, nA){
  rownum <- nrow(trainData)

  #對第nA列的特徵A計算頻數
  nA.freq <- count(trainData,nA)
  i <- 1
  sub.hd <- c()
  for (nA.value in nA.freq[,1]){
    #取特徵值A取值爲na.value的子集
    sub.trainData <- trainData[which(trainData[,nA] == nA.value),]

    sub.hd[i] <- cal_HD(sub.trainData,nClass)
    i <- i+1
  }

  nA.freq <- mutate(nA.freq, freq2 = (freq / rownum)*sub.hd)
  sum(nA.freq[,"freq2"])
}

##計算訓練集合D對特徵值A的信息增益g(D,A)
##輸入:trainData 訓練集,類型爲數據框
##      nClass 指明訓練集中第nClass列爲分類結果
##      nA 指明trainData中特徵A的列號
##輸出:訓練集trainData對特徵A的信息增益
g_DA <- function(trainData, nClass, nA){
  cal_HD(trainData, nClass) - cal_HDA(trainData, nClass, nA)
}

##根據訓練集合生成決策樹
##輸入:trainData 訓練集,類型爲數據框
##      strRoot 指明根節點的屬性名稱
##      strRootAttri 指明根節點的屬性取值
##      nClass 指明訓練集中第nClass列爲分類結果
##      cAttri 向量,表示當前可用的特徵集合,用列號表示
##      e 如果特徵的最大信息增益小於e,則剩餘作爲一個分類,類頻數最高的最爲分類結果
##輸出:決策樹T
gen_decision_tree <- function(trainData, strRoot, strRootAttri, nClass, cAttri, e){
  # 樹的描述,(上級節點名稱、上級節點屬性值、自己節點名稱,自己節點的取值)
  decision_tree <- data.frame()

  nClass.freq <- count(trainData,nClass)   ##類別出現的頻數
  nClass.freq <- arrange(nClass.freq, desc(freq))  ##按頻數從低到高排列
  col.name <- names(trainData) ##trainData的列名

  ##1、如果D中所有屬於同一類Ck,則T爲單節點樹  
  if nrow(nClass.freq) == 1{
    rbind(decision_tree, c(strRoot, strRootAttri, nClass.freq[1,1], ''))
    return decision_tree
  }

  ##2、如果屬性cAttri爲空,將D中頻數最高的類別返回
  if length(cAttri) == 0{
    rbind(decision_tree, c(strRoot, strRootAttri, nClass.freq[1,1], ''))
    return decision_tree
  }

  ##3、計算cAttri中各特徵值對D的信息增益,選擇信息增益最大的特徵值Ag及其信息增益
  maxDA <- 0    #記錄最大的信息增益
  maxAttriName <- ''   #記錄最大信息增益對應的屬性名稱
  maxAttriIndex <- ''   #記錄最大信息增益對應的屬性列號

  for(i in cAttri){
    curDA <- g_DA(trainData,nClass,i)
    if (maxDA <= curDA){
      maxDA <- curDA
      maxAttriName <- col.name[i]
    }
  }

  ##4、如果最大信息增益小於閾值e,將D中頻數最高的類別返回
  if (maxDA < e){
    rbind(decision_tree, c(strRoot, strRootAttri, nClass.freq[1,1], ''))
    return decision_tree
  }

  ##5、否則,對Ag的每一可能值ai,依Ag=ai將D分割爲若干非空子集Di
  ##   將Di中實例數最大的類作爲標記,構建子節點
  ##   由節點及其子節點構成樹T,返回T
  for (oneValue in unique(trainData[,maxAttriName])){
    sub.train <- trainData[which(trainData[,maxAttriName] == oneValue),]  #Di
    #sub.trian.freq <- count(sub.train,nClass)   ##類別出現的頻數
    #sub.trian.freq <- arrange(sub.trian.freq, desc(freq))  ##按頻數從低到高排列

    rbind(decision_tree, c(strRoot, strRootAttri, maxAttriName , oneValue))

    ##6、遞歸構建下一步
    # 剔除已經使用的屬性
    next.cAttri <- cAttri[which(cAttri !=maxAttriIndex)]
    # 遞歸調用
    next.dt <-gen_decision_tree(sub.train, maxAttriName,
                                oneValue, nClass, next.cAttri, e)
    rbind(decision_tree, next.dt)
  }

  names(decision_tree) <- c('preName','preValue','curName','curValue')
  decision_tree
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章