显示标签为“决策树”的博文。显示所有博文
显示标签为“决策树”的博文。显示所有博文

星期日, 十月 26, 2014

python的决策树和随机森林

Python的决策树和随机森林

决策树模型是一种简单易用的非参数分类器。它不需要对数据有任何的先验假设,计算速度较快,结果容易解释,而且稳健性强,对噪声数据和缺失数据不敏感。下面示范用titanic中的数据集为做决策树分类,目标变量为survive。

第一步:读取数据

In [2]:
%pylab inline
import pandas as pd
df = pd.read_csv('titanic.csv')
df.head()
#df.info()
Populating the interactive namespace from numpy and matplotlib

Out[2]:
survived pclass name sex age sibsp parch ticket fare cabin embarked
0 0 3 Braund, Mr. Owen Harris male 22 1 0 A/5 21171 7.2500 NaN S
1 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38 1 0 PC 17599 71.2833 C85 C
2 1 3 Heikkinen, Miss. Laina female 26 0 0 STON/O2. 3101282 7.9250 NaN S
3 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35 1 0 113803 53.1000 C123 S
4 0 3 Allen, Mr. William Henry male 35 0 0 373450 8.0500 NaN S

第二步:数据整理

  • 只取出三个自变量
  • 将将age缺失值进行补全
  • 将pclass变量转为三个哑变量
  • 将sex转为0-1变量
In [3]:
subdf = df[['pclass','sex','age']]
y = df.survived
# sklearn中的Imputer也可以
age = subdf['age'].fillna(value=subdf.age.mean())
# sklearn OneHotEncoder也可以
pclass = pd.get_dummies(subdf['pclass'],prefix='pclass')
sex = (subdf['sex']=='male').astype('int')
X = pd.concat([pclass,age,sex],axis=1)
X.head()
Out[3]:
pclass_1 pclass_2 pclass_3 age sex
0 0 0 1 22 1
1 1 0 0 38 0
2 0 0 1 26 0
3 1 0 0 35 0
4 0 0 1 35 1

第三步:建模

  • 数据切分为train和test
In [4]:
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=33)
  • 使用决策树观察在检验集表现
In [6]:
from sklearn import tree
clf = tree.DecisionTreeClassifier(criterion='entropy', max_depth=3,min_samples_leaf=5)
clf = clf.fit(X_train,y_train)
print "准确率为:{:.2f}".format(clf.score(X_test,y_test))
准确率为:0.83

  • 观察各变量的重要性
In [7]:
clf.feature_importances_
Out[7]:
array([ 0.08398076,  0.        ,  0.23320717,  0.10534824,  0.57746383])
  • 使用更多指标来评估模型
In [17]:
from sklearn import metrics
def measure_performance(X,y,clf, show_accuracy=True, 
                        show_classification_report=True, 
                        show_confusion_matrix=True):
    y_pred=clf.predict(X)   
    if show_accuracy:
        print "Accuracy:{0:.3f}".format(metrics.accuracy_score(y,y_pred)),"\n"

    if show_classification_report:
        print "Classification report"
        print metrics.classification_report(y,y_pred),"\n"
        
    if show_confusion_matrix:
        print "Confusion matrix"
        print metrics.confusion_matrix(y,y_pred),"\n"
        
measure_performance(X_test,y_test,clf, show_classification_report=True, show_confusion_matrix=True)
Accuracy:0.834 

Classification report
             precision    recall  f1-score   support

          0       0.85      0.88      0.86       134
          1       0.81      0.76      0.79        89

avg / total       0.83      0.83      0.83       223


Confusion matrix
[[118  16]
 [ 21  68]] 


  • 使用交叉验证来评估模型
In [8]:
from sklearn import cross_validation
scores1 = cross_validation.cross_val_score(clf, X, y, cv=10)
scores1
Out[8]:
array([ 0.82222222,  0.82222222,  0.7752809 ,  0.87640449,  0.82022472,
        0.76404494,  0.7752809 ,  0.76404494,  0.83146067,  0.78409091])

第三步:决策树画图

  • 需要安装GraphViz'
In [9]:
import pydot,StringIO
dot_data = StringIO.StringIO() 
In [14]:
tree.export_graphviz(clf, out_file=dot_data, feature_names=['age','sex','1st_class','2nd_class','3rd_class']) 
dot_data.getvalue()
pydot.graph_from_dot_data(dot_data.getvalue())
graph = pydot.graph_from_dot_data(dot_data.getvalue()) 
#graph.write_png('titanic.png') 
#from IPython.core.display import Image 
#Image(filename='titanic.png')

第四步:使用随机森林进行比较

In [11]:
from sklearn.ensemble import RandomForestClassifier
clf2 = RandomForestClassifier(n_estimators=1000,random_state=33)
clf2 = clf2.fit(X_train,y_train)
scores2 = cross_validation.cross_val_score(clf2,X, y, cv=10)
clf2.feature_importances_
Out[11]:
array([ 0.05526809,  0.02266161,  0.08156048,  0.46552672,  0.37498309])
In [12]:
scores2.mean(), scores1.mean()
Out[12]:
(0.81262938372488946, 0.80352769265690616)

星期三, 十一月 28, 2012

决策树之三国争霸


决策树是一种简洁实用的数据挖掘方法。在R中通常可以用rpart包和party包来实现两种算法的决策树。最近著名的C4.5决策树算法的升级版本C5.0已经可以在官网下载到。对于这三种决策树算法,本文来做一个预测效果的简单对比。

对比用的数据集是C50包中自带的churn数据,它是用来预测顾客流失的数据集,其中样本量为3333个,变量数为20个。为不平衡数据,没有缺失值存在。对比基本步骤是用10重交叉检验,将数据随机分为10份,用9份训练决策树,用1份来检验结果。循环后求出10个预测准确度的均值。然后在外面再套一个100次大循环,产生三个决策树算法各100个准确率。最后绘制为提琴图,从图中可以观察到C5.0的表现最好,而party次之,rpart的效果最差。在本例实验中最大的差距虽然不过0.02,但如果放在kaggle的数据挖掘比赛中,就相当于是一百位名次的差距了。

星期五, 七月 20, 2012

用gbm包实现随机梯度提升算法


中国有句老话:三个臭皮匠,顶个诸葛亮。这个说法至少在变形金刚中得到了体现,没有组合之前的大力神只是五个可以被柱子哥随手秒掉工地苦力。但组合之后却是威力大增。在机器学习领域也是如此,一堆能力一般的“弱学习器”也能组合成一个“强学习器”。前篇文章提到的随机森林就是一种组合学习的方法,本文要说的是另一类组合金刚:提升方法(Boosting)。提升方法是一大类集成分类学习的统称。它用不同的权重将基学习器进行线性组合,使表现优秀的学习器得到重用。在R语言中gbm包就是用来实现一般提升方法的扩展包。根据基学习器、损失函数和优化方法的不同,提升方法也有各种不同的形式。

自适应提升方法AdaBoost
它是一种传统而重要的Boost算法,在学习时为每一个样本赋上一个权重,初始时各样本权重一样。在每一步训练后,增加错误学习样本的权重,这使得某些样本的重要性凸显出来,在进行了N次迭代后,将会得到N个简单的学习器。最后将它们组合起来得到一个最终的模型。

梯度提升方法Gradient Boosting
梯度提升算法初看起来不是很好理解,但我们和线性回归加以类比就容易了。回忆一下线性回归是希望找到一组参数使得残差最小化。如果只用一次项来解释二次曲线一定会有大量残差留下来,此时就可以用二次项来继续解释残差,所以可在模型中加入这个二次项。

同样的,梯度提升是先根据初始模型计算伪残差,之后建立一个基学习器来解释伪残差,该基学习器是在梯度方向上减少残差。再将基学习器乘上权重系数(学习速率)和原来的模型进行线性组合形成新的模型。这样反复迭代就可以找到一个使损失函数的期望达到最小的模型。在训练基学习器时可以使用再抽样方法,此时就称之为随机梯度提升算法stochastic gradient boosting


星期日, 七月 15, 2012

随机森林及其副产品


随机森林(Random Forest)方法是Leo Breiman于2001年提出的一种集成学习(Ensemble Learning)方法,它是传统决策树方法的扩展,将多个决策树进行组合,来提高预测精度。随机森林利用分类回归树(CART)作为其基本组成单元,也可称之为基学习器或是子模型。CART在之前的文章中我们已经介绍过,就不再详细说明了。而集成学习的思路是试图通过连续调用单个学习算法,获得不同的学习器,然后根据规则组合这些学习器来解决同一个问题,可以显著的提高学习系统的泛化能力。组合多个学习器主要采用加权平均或投票的方法。常见的集成学习算法还包括了装袋算法(Bagging)和提升算法(Boosting)。

1. 随机森林计算步骤

  • 从原始训练样本中随机有放回抽出N个样本;
  • 从解释变量中随机抽出M个变量;
  • 依据上述得到的子集实施CART方法(无需剪枝),从而形成一个单独的决策树;
  • 重复上面步骤X次,就构建了有X棵树的随机森林模型。
  • 在对新数据进行预测分类时,由X棵树分别预测,以投票方式综合最终结果。

星期六, 六月 16, 2012

基于模型的决策树


线性模型是很常用的一类建模方法,它可以用于回归和分类问题。但有时候用全体数据来建模并不理想,这是因为数据内部存在一些局部特性。例如我们要考虑教育对收入的影响程度,那么对于不同的性别,这个影响程度可能也是不同的。所以我们会将数据先进行分割,然后对每个组分别进行回归建模。这种模型和分割相结合的方法又称为基于模型的递归分割算法(model-based recursive partitioning algorithm)。这个工作可以通过手工分组或加入虚拟变量来做,更方便的是利用party包中的mob函数来完成。
mob函数算法的基本步骤如下:
  • 对所有数据构建线性模型
  • 根据不同的分割变量,评价模型参数的不稳定性。选择某个分割变量使模型参数不稳定性最大。
  • 计算分割变量的分割点
  • 将数据根据上述结果分成两个子集
  • 重复上面的步骤

下面的算例来自于faraway包中的psid数据集,其中我们关注的是不同性别的组中,教育对收入的影响。
library(party)
data(psid, package = "faraway")
mod1 <- mob(sqrt(income) ~ educ | sex, data = psid)
plot(mod1)
plot of chunk unnamed-chunk-1
可以观察到男性组别中,教育对收入的影响显然要更大一些。mob函数也可以处理两分类变量,下面的算例来自于mlbench包中的PimaIndiansDiabetes2数据集,其中我们关注的是对糖尿病风险的影响因素。
data(PimaIndiansDiabetes2, package = "mlbench")
data <- na.omit(PimaIndiansDiabetes2[, -c(4, 5)])
mod2 <- mob(diabetes ~ glucose | pregnant + pressure + mass + pedigree + 
    age, data = data, model = glinearModel, family = binomial())
plot(mod2)
plot of chunk unnamed-chunk-2
从上图可以观察到,首先将数据根据体重变量mass进行了分组。在体重较轻的一组即结点2中,糖尿病发病风险较低,但随着血糖浓度glucose的增加,风险也在急剧增加。在结点4中表示了体重较大但年龄小于30的人群,糖尿病发病风险整体上升。而结点5中表示了体重较大且年龄大于30的人群,糖尿病发病风险达到最大,随着血糖浓度的增加,风险也在逐步增加。
参考资料:
http://cran.r-project.org/web/packages/party/vignettes/MOB.pdf
顺便说下,本文是采用knitr包+markdown+Rstudio生成html后,贴在博客上的,语法高亮木有了,整体效果不算很好。

星期四, 五月 17, 2012

rpart包和party包的简单比较


决策树模型是一种简单易用的非参数分类器。它不需要对数据有任何的先验假设,计算速度较快,结果容易解释,而且稳健性强,不怕噪声数据和缺失数据。决策树模型的基本计算步骤如下:先从n个自变量中挑选一个,寻找最佳分割点,将数据划分为两组。针对分组后数据,将上述步骤重复下去,直到满足某种条件。

在决策树建模中需要解决的重要问题有三个:

  • 如何选择自变量
  • 如何选择分割点
  • 确定停止划分的条件

在R语言中关于决策树建模,最为常用的有两个包,一个是rpart包,另一个是party包。我们来看一下对于上述问题,这两个包分别是怎么处理的。


星期四, 七月 28, 2011

在R语言中对回归树模型、装袋算法与随机森林之间的简单比较

回归树模型在之前的博客文章中已有介绍。而装袋算法与随机森林相对而言会生成多个树模型,再进行组合预测,其效果远大于单个树模型。装袋算法(bagging)采取自助法的思路,从样本中随机抽样,形成多个训练样本,生成多个树模型。然后以多数投票的方式来预测结果。随机森林则(randomForest)更进一步,不仅对样本进行抽样,还对变量进行抽样。下面来横向对比一下各算法。

首先读入必要的程序包
library(DMwR)
library(rpart)
library(ipred)
library(randomForest)

前二种算法可以计算缺失数据,但随机森林不行,所以还需将数据进行清洗整理

星期四, 六月 09, 2011

分类-回归树模型(CART)在R语言中的实现

CART模型,即Classification And Regression Trees。它和一般回归分析类似,是用来对变量进行解释和预测的工具,也是数据挖掘中的一种常用算法。如果因变量是连续数据,相对应的分析称为回归树,如果因变量是分类数据,则相应的分析称为分类树。

决策树是一种倒立的树结构,它由内部节点、叶子节点和边组成。其中最上面的一个节点叫根节点。 构造一棵决策树需要一个训练集,一些例子组成,每个例子用一些属性(或特征)和一个类别标记来描述。构造决策树的目的是找出属性和类别间的关系,一旦这种关系找出,就能用它来预测将来未知类别的记录的类别。这种具有预测功能的系统叫决策树分类器。其算法的优点在于:1)可以生成可以理解的规则。2)计算量相对来说不是很大。3)可以处理多种数据类型。4)决策树可以清晰的显示哪些变量较重要。

下面以一个例子来讲解如何在R语言中建立树模型。为了预测身体的肥胖程度,可以从身体的其它指标得到线索,例如:腰围、臀围、肘宽、膝宽、年龄。