统计-可能是最丰富的随机森林攻略+代码放送

关于随机森林,你要知道:

  • 基于决策树,比决策树更加稳定的分类器
  • 无监督,随机抽取组成小样本。再放回,再抽取,即bootstrap
  • 建树足够多,没用的树就会被抵消。树越多,模型精确度越高,增加到一定程度后变缓
  • 可能会过拟合。当样本数量小于变量数量时,会发生过拟合,即用一个方程,求解两个未知数。

构建过程:

第一步 构建bootstrap

  • 从原来数据集中随机挑选样本构建新的数据集,同一个样本可以挑选两次

第二步 建立决策树

  • 用bootstrap的数据集构建决策树
  • 但是每构建一步决策树,只能用bootstrap数据集变量的子集
  • 如图中,表里显示有五个变量,但每次构建决策树,只能用<=5个变量。


第三步 重复这个过程若干次

  • 这就是若干个决策树,随机森林让结果更加准确


问题:

  • 原数据集中有1/3的数据在bootstrap中,没有落入新产生的数据集,这部分称为 out-of-bag dataset
  • 这一部分out-of-bag dataset容易产生分类错误,我们称为out-of-bag error

代码实战

1. 获取数据。我们选择UCI上的machine learning的数据集

library(ggplot2)
library(cowplot)
library(randomForest)
url <- "http://archive.ics.uci.edu/ml/machine-learning-databases/heart-disease/processed.cleveland.data"
data <- read.csv(url, header=FALSE)
colnames(data) <- c(
  "age",
  "sex",# 0 = female, 1 = male
  "cp", # chest pain
  # 1 = typical angina,
  # 2 = atypical angina,
  # 3 = non-anginal pain,
  # 4 = asymptomatic
  "trestbps", # resting blood pressure (in mm Hg)
  "chol", # serum cholestoral in mg/dl
  "fbs",  # fasting blood sugar greater than 120 mg/dl, 1 = TRUE, 0 = FALSE
  "restecg", # resting electrocardiographic results
  # 1 = normal
  # 2 = having ST-T wave abnormality
  # 3 = showing probable or definite left ventricular hypertrophy
  "thalach", # maximum heart rate achieved
  "exang",   # exercise induced angina, 1 = yes, 0 = no
  "oldpeak", # ST depression induced by exercise relative to rest
  "slope", # the slope of the peak exercise ST segment
  # 1 = upsloping
  # 2 = flat
  # 3 = downsloping
  "ca", # number of major vessels (0-3) colored by fluoroscopy
  "thal", # this is short of thalium heart scan
  # 3 = normal (no cold spots)
  # 6 = fixed defect (cold spots during rest and exercise)
  # 7 = reversible defect (when cold spots only appear during exercise)
  "hd" # (the predicted attribute) - diagnosis of heart disease
  # 0 if less than or equal to 50% diameter narrowing
  # 1 if greater than 50% diameter narrowing
)
head(data)

2. 清洗数据

str(data)
发现,sex, cp, fbs, restecg等明明是factor类型,但这里给的是num。另外有些地方填充的是?,需要改成NA
## First, replace "?"s with NAs.
data[data == "?"] <- NA

## Now add factors for variables that are factors and clean up the factors
## that had missing data...
data[data$sex == 0,]$sex <- "F"
data[data$sex == 1,]$sex <- "M"
data$sex <- as.factor(data$sex)

data$cp <- as.factor(data$cp)
data$fbs <- as.factor(data$fbs)
data$restecg <- as.factor(data$restecg)
data$exang <- as.factor(data$exang)
data$slope <- as.factor(data$slope)

data$ca <- as.integer(data$ca)
data$ca <- as.factor(data$ca)  # ...then convert the integers to factor levels

data$thal <- as.integer(data$thal) # "thal" also had "?"s in it.
data$thal <- as.factor(data$thal)

## This next line replaces 0 and 1 with "Healthy" and "Unhealthy"
data$hd <- ifelse(test=data$hd == 0, yes="Healthy", no="Unhealthy")
data$hd <- as.factor(data$hd)

3. 构建模型

  • 大多数的机器学习模型,需要人为把数据集划分成训练集和验证集,但是随机森林省去了这步,因为它用了bootstrap,不是所有的数据集都用来建树。
  • 训练数据集是bootstrap数据,验证数据集是剩下的样本,又称为out-of-bag data (OOB)

a) 先用临近值填补缺失值

set.seed(43)
data.imputed<-rfImpute(hd~.,data=data,iter=6)

iter: 迭代数 breiman说4-6次就好,过多的迭代数不会让OOB error变小
set.seed:保证抽取的过程是随机的
hd~: 我们想通过所有参数预测hd


红框部分为每次迭代的OOB error


b) 构建随机森林模型

model <- randomForest(hd ~ ., data=data.imputed, proximity=TRUE)

mtry:
如果我们想预测的是连续变量,该值为总的变量值/3
如果想预测的是factor,该值为总变量数的根号
本例子中,hd是factor,mtry的默认值为sqrt(13)=3.6约等于3


number of tree:500 种树个数,默认500个
no. of variables tried at each split: 3 (即mtry)节点个数
OOB误差:17.82% 这个很重要
cofusion matrix的意义
22个unhealthy被分入healthy中
32个healthy被分入unhealthy中


c) 更换mtry和number of trees的数量,使随机森林达到最优
核心思想:使OOB,healthy, unhealthy的error rate达到最低

model$err.rate

横行:种的第i颗树,i=1:500,依次类推
纵行:OOB error rate; healthy error rate; unhealthy error rate

  • 整理出矩阵,画图
oob.error.data <- data.frame(
  Trees=rep(1:nrow(model$err.rate), times=3),
  Type=rep(c("OOB", "Healthy", "Unhealthy"), each=nrow(model$err.rate)),
  Error=c(model$err.rate[,"OOB"],
          model$err.rate[,"Healthy"],
          model$err.rate[,"Unhealthy"]))

ggplot(data=oob.error.data, aes(x=Trees, y=Error)) +
  geom_line(aes(color=Type))


可以看出:当树种到400以后,三者的误差基本不变了

  • 那么种1000颗树会怎样呢?
model <- randomForest(hd ~ ., data=data.imputed, ntree=1000, proximity=TRUE)
model

oob.error.data <- data.frame(
  Trees=rep(1:nrow(model$err.rate), times=3),
  Type=rep(c("OOB", "Healthy", "Unhealthy"), each=nrow(model$err.rate)),
  Error=c(model$err.rate[,"OOB"],
          model$err.rate[,"Healthy"],
          model$err.rate[,"Unhealthy"]))

ggplot(data=oob.error.data, aes(x=Trees, y=Error)) +
  geom_line(aes(color=Type))

500-1000之间,误差基本不变,因此选500颗树就好

  • 更换mtry值,找到误差最低的mtry值
oob.values <- vector(length=10)
for(i in 1:10) {
  temp.model <- randomForest(hd ~ ., data=data.imputed, mtry=i, ntree=1000)
  oob.values[i] <- temp.model$err.rate[nrow(temp.model$err.rate),1]
}
oob.value

可以看出, mtry在3左右就很好,再低容易引起过拟合

4. 应用多维尺度变换(MDS)查看样本之间的距离,即拟合效果

具体原理参照我之前的帖子

  • 将proximity matrix转化成distance matrix
distance.matrix <- dist(1-model$proximity)
mds.stuff <- cmdscale(distance.matrix, eig=TRUE, x.ret=TRUE)
  • 计算每个MDS轴占据的百分比
mds.var.per <- round(mds.stuff$eig/sum(mds.stuff$eig)*100, 1)
  • 画图
mds.values <- mds.stuff$points
mds.data <- data.frame(Sample=rownames(mds.values),
                       X=mds.values[,1],
                       Y=mds.values[,2],
                       Status=data.imputed$hd)

ggplot(data=mds.data, aes(x=X, y=Y, label=Sample)) +
  geom_text(aes(color=Status)) +
  theme_bw() +
  xlab(paste("MDS1 - ", mds.var.per[1], "%", sep="")) +
  ylab(paste("MDS2 - ", mds.var.per[2], "%", sep="")) +
  ggtitle("MDS plot using (1 - Random Forest Proximities)")

可见我们的随机森林效果不错, healthy分成一类,unhealthy分成一类

5. 查看每个变量的重要性评分

注意:importance=TRUE必须得打开,否则没法进行重要性评分

model <- randomForest(hd ~ ., data=data.imputed, proximity=TRUE,importance=TRUE)
importance(model,type=1)
importance(model,type=2)
varImpPlot(model)     


  • type=1 重要性评分 袋外数据自变量值发生轻微扰动后的分类正确率与扰动前分类正确率的平均减少量。即计算精度下降,平均精度的减少值。越大说明这个变量越重要
  • type=2 gini指数 节点纯度,越大纯度越低
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容