1.决策树
2.随机森林
1.决策树(decision tree)
决策树一种简单的非线性模型,用来解决回归与分类问题。
通常是重复的将训练集解释变量分割成子集的过程。决策树的节点用方块表示,用来测试解释变量。
每个节点向下的边表示不同决策产生结果。训练集的样本由决策结果分成不同的子集。例如,一个节点测试解释变量的值是否超过的限定值。如果没有超过,则进入该节点的右侧子节点;如果超过,则进入左侧子节点。子节点的运行原理和前面的一样,直到终止条件(stopping criterion)满足才停止。在分类任务中,包含在叶子节点中的样本响应变量的值的平均值作为响应变量的估计值。
决策树建立之后,做决策的过程就是把测试样本放进决策树沿着边不断前进,直到一个叶子被触及才停止前进。
训练决策树:
常用的方法:
ID3(Iterative Dichotomiser 3,迭代二叉树3代),决策树需要对每条边的解释变量进行检查。每条边的下一个节点由测试结果决定。决策树也是通过对解释变量序列的逐条测试获取响应变量结果的。那么,哪个解释变量应该先测试?如果子集成员种类不同,我们还是不能确定种类。我们还需要避免创建那种测试,这些测试极少可以分出一个样本的种类,也不能降低分类不确定性。能够降低分类不确定性的测试通常都是最好的测试。
我们通常用熵(entropy)来度量信息的不确定性。以比特(bits)为计量单位,熵量化了一个变量的不确定性。熵计算公式如下所示:
其中,n 是样本的数量,P(xi) 是第 个样本的概率。b 一般取 2,e 或10 。因为对数函数中真数小于1
则对数值为0,因此,公式前面加符号使熵为正数。
例如,一个硬币投掷一次事件发生后一般有两种可能:正面或反面。正面朝上的概率是0.5,反面朝
上的概率也是0.5。那么一个硬币投掷一次的结果这个变量的熵:
H(X) = −(0.5 0.5 + 0.5 0.5) = 1.0
也就是说,两个等概率的可能值,正面和反面,只需要一个比特。如果是两个硬币投掷一次事件发生
后一般有四种可能:正面正面,正面反面,反面反面,反面正面,每种可能的概率是0.25。其熵为:
如果硬币的两面相同,那么表示其可能值的变量熵为0比特,也就是说,结果是确定的,变量再也不
会产生新信息量了。熵还可以用小数值表示。比如,一个不正常的硬币,其正反面的材质不同,一边
重一边轻。导致其投掷后正面朝上的概率0.8,反面朝上概率0.2。那么其熵为:
一个不正常的硬币投掷后其结果的熵是一个小数。虽然两种结果都有可能,但是因为其中一种可能性
更大,所有不确定性减小了。
而我们的问题并没有消除许多可能性。因此,要用一种方法来合理度量熵的降幅,这个方法称为信息增益(information gain)。信息增益是父节点熵,用 表示与其子节点熵的加权均值的差,计算公式如下:
其中,
表示解释变量 的样本 。
表示解释变量 的值等于 样本数量。
还有很多算法也可以实现决策树,C4.5算法是ID3的改进版,可以用来处理连续的解释变量并考虑特征值丢失。C4.5算法可以修剪(prune)决策树,修剪是通过更少的叶节点来替换分支,以缩小决策树的规模。scikit-learn的决策树实现算法是CART(Classification and Regression Trees,分类与回归树)算法,CART也是一种支持修剪的学习算法。
基尼不纯度
除了最大信息增益建立决策树,还可以用基尼不纯度(Gini impurity),度量一个集合中每种类型的比例。基尼不纯度格式如下:
其中,j 是类型的数量,t 是节点样本的子集,P(i|t) 是从节点子集中选择一个类型 的概率。
可以看出,如果集合中只有一类,那么基尼不纯度值为0。和熵一样,当每个类型概率相同时,基尼
不纯度最大。此时,基尼不纯度的最大值有类型的数量决定:
我们的例子有两种类型,所有基尼不纯度的最大值是0.5。scikit-learn研究决策树的算法,既支持信
息增益,也支持基尼不纯度。到底用哪种方法并没有规定,实际上,它们产生的结果类似。一般的决
策树都是两个都用,比较一下结果,哪个好用哪个。
#scikit-learn决策树
用scikit-learn的决策树来做一个广告屏蔽程序,这个程序可以预测出网页上的图片是广告
还是正常内容。被确认是广告的图片通过调整CSS隐藏。
数据源:互联网广告数据集(Internet
Advertisements Data Set) (http://archive.ics.uci.edu/ml/datasets/Internet+Advertisements)
来实现分类器,里面包含了3279张图片。不过类型的比例并不协调,459幅广告图片,2820幅正常内容。决
策树学习算法可以从比例并不协调的数据集中生成一个不平衡的决策树(biased tree)。
首先对模型进行评估,本例的解释变量就是图片的尺寸,网址链接里的单词,以及图片标签周围的单词。响应变量就是图片的类型。解释变量已经被转换成特征向量了。前三个特征值表示宽度,高度,图像纵横比(aspect ratio)。剩下的特征是文本变量的二元频率值。下面,用网格搜索来确定决策树模型最大最优评价效果(F1 score)的超参数,然后把决策树用在测试集进行效果评估。
import pandas as pd
from sklearn.tree import DecisionTreeClassifier
from sklearn.cross_validation import train_test_split
from sklearn.metrics import classification_report
from sklearn.pipeline import Pipeline
from sklearn.grid_search import GridSearchCV
#读取数据,源数据是zip,可以解压后再读取,也可以import zipfile,读取压缩数据
df = pd.read_csv(r'D:\每日工作\学习笔记\test\mlslpic\ad-dataset\ad.data', header=None)
explanatory_variable_columns = set(df.columns.values)
response_variable_column = df[len(df.columns.values)-1]
# The last column describes the targets
explanatory_variable_columns.remove(len(df.columns.values)-1)
y = [1 if e == 'ad.' else 0 for e in response_variable_column]
X = df.loc[:, list(explanatory_variable_columns)]
X.replace(to_replace=' *\?',value=-1, regex=True, inplace=True)
X_train,X_test, y_train, y_test = train_test_split(X,y)
pipeline = Pipeline([
('clf',DecisionTreeClassifier(criterion='entropy'))
])
parameters = {
'clf__max_depth': (150, 155, 160),
'clf__min_samples_split': (1, 2, 3),
'clf__min_samples_leaf': (1, 2, 3)
}
grid_search = GridSearchCV(pipeline, parameters, n_jobs=-1,verbose=1, scoring='f1')
grid_search.fit(X_train, y_train)
print ('最佳效果:%0.3f' %grid_search.best_score_)
print('最优参数')
best_parameters = grid_search.best_best_parameters = grid_search.best_estimator_.get_params()
for param_name in sorted(parameters.keys()):
print('\t%s: %r' % (param_name, best_parameters[param_name]))
predictions = grid_search.predict(X_test)
print (classification_report(y_test, predictions))
precision recall f1-score support
out:
Fitting 3 folds for each of 27 candidates, totalling 81 fits
[Parallel(n_jobs=-1)]: Done 42 tasks | elapsed: 8.8s
[Parallel(n_jobs=-1)]: Done 81 out of 81 | elapsed: 13.9s finished
最佳效果:0.888
clf__max_depth: 150
clf__min_samples_leaf: 3
clf__min_samples_split: 3
0 0.98 0.98 0.98 710
1 0.87 0.85 0.86 110
avg / total 0.96 0.96 0.96 820
#这个分类器发现了测试集中90%的广告,真广告中87%被模型发现了。
2.决策树集成,随机森林
集成学习方法将一堆模型组合起来使用,比单个模型可以获取更好的效果。
随机森林(randomforest) 是一种随机选取训练集解释变量的子集进行训练,获得一系列决策树的集合的方法。
随机森林通常用其决策树集合里每个决策树的预测结果的均值或众数作为最终的预测值。
scikit-learn里的随机森林使用均值作为预测值。随机森林相比单一决策树,不太会受到拟合过度的影响,因为随机森林的
每个决策树都看不到训练集的全貌,只是训练一部分解释变量数据,不会记忆训练集的全部噪声。
用随机森林升级广告屏蔽程序,把前面DecisionTreeClassifier替换成RandomForestClassifier就可以了。仍然用网格搜索来探索最优超参数。
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.cross_validation import train_test_split
from sklearn.metrics import classification_report
from sklearn.pipeline import Pipeline
from sklearn.grid_search import GridSearchCV
#读取数据,源数据是zip,可以解压后再读取,也可以import zipfile,读取压缩数据
df = pd.read_csv(r'D:\每日工作\学习笔记\test\mlslpic\ad-dataset\ad.data', header=None)
explanatory_variable_columns = set(df.columns.values)
response_variable_column = df[len(df.columns.values)-1]
# The last column describes the targets
explanatory_variable_columns.remove(len(df.columns.values)-1)
y = [1 if e == 'ad.' else 0 for e in response_variable_column]
X = df.loc[:, list(explanatory_variable_columns)]
X.replace(to_replace=' *\?',value=-1, regex=True, inplace=True)
X_train,X_test, y_train, y_test = train_test_split(X,y)
pipeline = Pipeline([
('clf',RandomForestClassifier(criterion='entropy'))
])
parameters = {
'clf__max_depth': (150, 155, 160),
'clf__min_samples_split': (1, 2, 3),
'clf__min_samples_leaf': (1, 2, 3)
}
grid_search = GridSearchCV(pipeline, parameters, n_jobs=-1,verbose=1, scoring='f1')
grid_search.fit(X_train, y_train)
print ('最佳效果:%0.3f' %grid_search.best_score_)
print('最优参数')
best_parameters = grid_search.best_best_parameters = grid_search.best_estimator_.get_params()
for param_name in sorted(parameters.keys()):
print('\t%s: %r' % (param_name, best_parameters[param_name]))
predictions = grid_search.predict(X_test)
print (classification_report(y_test, predictions))
out:
Fitting 3 folds for each of 27 candidates, totalling 81 fits
[Parallel(n_jobs=-1)]: Done 42 tasks | elapsed: 8.3s
[Parallel(n_jobs=-1)]: Done 81 out of 81 | elapsed: 12.3s finished
最佳效果:0.923
clf__max_depth: 150
clf__min_samples_leaf: 1
clf__min_samples_split: 3
precision recall f1-score support
0 0.98 0.99 0.98 710
1 0.91 0.87 0.89 110
avg / total 0.97 0.97 0.97 820
#这个分类器发现了测试集中91%的广告,各类指标相比单一决策树都有明显改善。精确率和召回率都提升到97%。
3.总结:
决策树的优劣势
决策树的用法更简单。首先,决策树对数据没有零均值,均方差的要求。而且可以容忍解释变量值的缺失,虽然现在的scikit-learn还没实现这一特点。决策树在训练的时
候可以忽略与任务无关的解释变量。
小型决策树很容易理解,而且可以通过scikit-learn的tree模块里的export_graphviz函数生成图形,可视化效果好。决策树的分支都有着逻辑上的联接关系,很容易通过流程图画出来。另外,决策
树支持多输出任务,单一决策树可以用于多类分类,不需要使用one-versus-all策略。
决策树是一种积极学习方法(eager learner),必须在它们可以用于预测测试集任务时,先从训练集建立一个与后面的需求无关的模型,但是模型一旦建好它们可以很快的预
测出结果。相反,有些算法是消极学习方法(lazy learners),像K最近邻(K-Nearest Neighbor,KNN)分类算法,它们必须等到有了训练集数据的预测需求,才会开始学习整个数据的特征。
消极学习方法不需要花时间训练预测能力,但是比积极学习方法预测速度慢。
决策树比之前介绍的算法更容易拟合过度,因为它们可以通过精确的描述每个训练样本的特征,构建出复杂的决策树,从而忽略了一般性的真实关联关系。有一些技术可以修正决策树的拟合过度。
修剪就是一个常用的策略,将决策树里一些最高的子节点和叶子节点剪掉,但是目前scikit-learn还没有相应的实现。但是,类似的效果可以通过设置决策树最大深度,或者限定只有当决策树包含的训练
样本数量超过限定值时才创建子节点。DecisionTreeClassifier和DecisionTreeRegressor类都有这样的参数可以设置。另外,随机森林决策树也可以消除拟合过度。
像ID3这样的决策树学习算法是贪婪的(greedy)。它们充分的学习有时会深陷于局部最优的美梦,但是不能保证生成最优决策树。ID3通过选择解释变量序列进行测试。一个解释变量被选中是因为它比其他解释变量更大幅度的降低了不确定性。但是,有可能全局最优的决策并非局部最优。
在例子中,决策树的规模并不重要,因为我们可以获取所有节点。但是,在现实应用中,决策树的规模被修剪以及其他技术限制。而决策树经过修剪后的不同形状会产生不同的效果。实际上,由信息增益和基尼不纯度启发式方法计算出的局部最优决策通常都会生成一个可行的决策树。