引言
随机森林的原理网上有一大堆,作为入门小白,下面来根据教材敲两个随机森林的代码。
随机森林有两个比较重要的参数:max_features 和 n_estimators。
max_features 的取值越高,随机森林里的每一颗决策树就会“长得更像”。如果max_features 的取值越低,就会迫使每颗决策树的样子更加不同,而且因为特征太少,决策树们不得不制造更多节点来拟合数据。
n_estimators 控制随机森林中决策树的数量。随机森林构建完成之后,每颗决策树都会单独进行预测。如果是用来进行回归分析的话,随机森林会把所有决策树预测的值取平均数;如果是用来进行分类的话,在森林内部会进行“投票”,每棵树预测数数据类别的概率,随机森林会把这些概率取平均值,然后把样本放入概率较高的分类中。
注释:
sklearn.ensemble.RandomForestClassifie 随机森林
函数原型:
class sklearn.ensemble.RandomForestClassifier(
n_estimators=10,
criterion='gini',
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0,
max_features=’auto’,
max_leaf_nodes=None,
min_impurity_decrease=0.0,
min_impurity_split=None,
bootstrap=True,
oob_score=False,
n_jobs=1,
random_state=None,
verbose=0,
warm_start=False,
class_weight=None)参数解释:
n_estimators:整数,可选择(默认值为10)。 森林里(决策)树的数目。
criterion:字符串,可选择(默认值为“gini”)。衡量分裂质量的性能(函数)。 受支持的标准是基尼不纯度的"gini",和信息增益的"entropy"(熵)。
注意:这个参数是特定树的。
首先Gini不纯度和Gini系数(coefficient)没有关系。Gini impurity衡量的是从一个集合中随机选择一个元素,基于该集合中标签的概率分布为元素分配标签的错误率。对于任何一个标签下的元素,其被分类正确的条件概率可以理解为在选择元素时选中该标签的概率与在分类时选中该标签的概率。基于上述描述,Gini impurity的计算就非常简单了,即1减去所有分类正确的概率,得到的就是分类不正确的概率。若元素数量非常多,切所有元素单独属于一个分类时,Gini不纯度达到极小值0
max_features: 整数,浮点数,字符串或者无值。寻找最佳分割时需要考虑的特征数目:
- 如果是int,就要考虑每一次分割处的max_feature特征
- 如果是float,那么max_features就是一个百分比,那么(max_feature*n_features)特征整数值是在每个分割处考虑的。
- 如果是auto,那么max_features=sqrt(n_features),即n_features的平方根值。
- 如果是log2,那么max_features=log2(n_features)
- 如果是None,那么max_features=n_features
注意:寻找分割点不会停止,直到找到最少一个有效的节点划分区,即使它需要有效检查超过max_features的特征。
max_depth:整数或者无值。(决策)树的最大深度。如果值为None,那么会扩展节点,直到所有的叶子是纯净的,或者直到所有叶子包含少于min_sample_split的样本。
min_samples_split:整数,浮点数。分割内部节点所需要的最小样本数量:
~如果为int,那么考虑min_samples_split作为最小的数字。
~如果为float,那么min_samples_split是一个百分比,并且把ceil(min_samples_split*n_samples)是每一个分割最小的样本数量。
在版本0.18中更改:为百分比添加浮点值。
min_samples_leaf:整数,浮点数。一个叶子节点所需要的权重总和(所有的输入样本)的最小加权分数。当sample_weight没有提供时,样本具有相同的权重。
max_leaf_nodes:整数或者无值。以最优的方法使用max_leaf_nodes来生长树。最好的节点被定义为不纯度上的相对减少。如果为None,那么不限制叶子节点的数量。
min_impurity_split:浮点数。树早期生长的阈值。如果一个节点的不纯度超过阈值那么这个节点将会分裂,否则它还是一片叶子。
自0.19版以后不推荐使用:min_impurity_split已被弃用,取而代之的是0.19中的min_impurity_decrease。min_impurity_split将在0.21中被删除。 使用min_impurity_decrease。
min_impurity_decrease:浮点数。如果节点的分裂导致的不纯度的下降程度大于或者等于这个节点的值,那么这个节点将会被分裂。
bootstrap:bool。是否使用袋外样本来估计泛化精度。
n_jobs:整数。用于拟合和预测的并行运行的工作(作业)数量。如果值为-1,那么工作数量被设置为核的数量。
random_state: 整数,RandomState实例,或者为None。RandomStateIf int,random_state是随机数生成器使用的种子; 如果是RandomState实例,random_state就是随机数生成器; 如果为None,则随机数生成器是np.random使用的RandomState实例。
verbose:整数。控制决策树建立过程的冗余度
warm_start:布尔值。当被设置为True时,重新使用之前呼叫的解决方案,用来给全体拟合和添加更多的估计器,反之,仅仅只是为了拟合一个全新的森林。
class_weight:字典,字典序列,"balanced"。“balanced_subsample” 或者None,(默认值为None),与格式{class_label: weight}相关联的类的可选的权值。如果没有给值,所有的类到都应该有一个权值。对于多输出问题,一个字典序列可以按照y的列的顺利被提供。
请注意,对于多输出(包括多标签),其权值应该被定义为它自己字典的每一列的每一个类。例如,对于四类多标签分类,权值应该如[{0: 1, 1: 1}, {0: 1, 1: 5}, {0: 1, 1: 1}, {0: 1, 1: 1}] 这样,而不是[{1:1}, {2:5}, {3:1}, {4:1}].这样。
"balanced"模式使用y的值来自动的调整权值,与输入数据中类别频率成反比,如:
n_samples / (n_classes * np.bincount(y))
"balanced_subsample"模式和"balanced"相同,除了权值是基于每棵成长树有放回抽样计算的。
对于多输出,y的每列权值将相乘。
请注意,如果指定了sample_weight,这些权值将会和sample_weight相乘(通过拟合方法传递)。
一、红酒的分类
数据采用datasets里的 红酒数据
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.model_selection import train_test_split #切分训练集和测试集
from sklearn.ensemble import RandomForestClassifier #导入随机森林模型
from sklearn import tree, datasets
#载入红酒数据
wine = datasets.load_wine()
#只选取前两个特征
X = wine.data[:, :2]
y = wine.target
#拆分训练集和数据集
X_train, X_test, y_train, y_test = train_test_split(X, y)
#设定随机森林中有6颗树
forest = RandomForestClassifier(n_estimators=6, random_state=3)
#拟合数据
forest.fit(X_train, y_train)
#绘制图形
#定义图像中分区的颜色和散点的颜色
cmap_light= ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF'])
#分别用样本的两个特征值创建图像和横轴和纵轴
x_min, x_max = X[:,0].min()-1, X[:,0].max()+1
y_min, y_max = X[:,1].min()-1, X[:,1].max()+1
#用不同的背景色表示不同的类
xx, yy = np.meshgrid(np.arange(x_min, x_max, .02),
np.arange(y_min, y_max, .02))
z = forest.predict(np.c_[(xx.ravel(), yy.ravel())]).reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx, yy, z, cmap=cmap_light)
#用散点把样本标出来
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold, edgecolors='k', s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title('Classifier: RandomForestClassifier') #依照参数值修改标题
plt.show()
运行结果如下图可示,随机森林的分类比较细腻,可调节参数查看分类器的表现
二、要不要和相亲对象进一步发展
采用美国1994 年采集的的成年人数据集,包括年龄、工作单位性质、学历等。下完之后是.data格式,重命名为.csv
数据集从这个地址下载:archive.ics.uci.edu/ml/machine-learning-databases/adult/
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.model_selection import train_test_split #切分训练集和测试集
from sklearn.ensemble import RandomForestClassifier #导入随机森林模型
from sklearn.tree import DecisionTreeClassifier #导入决策树模型
import graphviz
from sklearn.tree import export_graphviz #导入决策树中输出graphviz的接口
from sklearn.externals.six import StringIO
#载入数据集
data = pd.read_csv('adult.csv', header=None, index_col=False, names=['年龄', '单位性质', '权重', '学历', '受教育时长', '婚姻状况',
'职业', '家庭情况', '种族', '性别', '资产所得', '资产损失',
'周工作时长','原籍', '收入'])
#只取部分数据
data_lite = data[['年龄', '单位性质', '学历', '性别', '周工作时长', '职业', '收入']]
#查看前5条数据
print('>>>>>>>>>>>原始数据前5行')
print(data_lite.head(5))
#使用 get_dummies 处理数据,将文本数据转化为数值,将特征值拆开,转换为0,1
data_dummie = pd.get_dummies(data_lite)
#对比原始特征和虚拟变量特征
print('样本原始特征:\n', list(data_lite.columns), '\n')
print('虚拟变量特征:\n', list(data_dummie.columns), '\n')
print(list(data_dummie.columns)[:-2])
#查看前5条数据
print('>>>>>>>>>>>get_dummies 处理后数据前5行')
print(data_dummie.head(5))
#定义数据集的特征值
features = data_dummie.loc[:,'年龄':'职业_ Transport-moving']
#将特征数值赋值给X
X = features.values
#将收入大于50k作为预测目标
y = data_dummie['收入_ >50K'].values
#拆分训练集和数据集
X_train, X_test, y_train, y_test = train_test_split(X, y)
#用最大深度为5 的决策树拟合数据
clf = DecisionTreeClassifier(max_depth=6)#依次取max_depth=1, 3, 5 查看结果
clf.fit(X_train, y_train)
#用随机森林拟合数据
forest = RandomForestClassifier(n_estimators=6, random_state=2)
forest.fit(X_train, y_train)
print('代码运行结果为:')
print('==========================')
print("决策树训练数据得分:{:.2f}".format(clf.score(X_test, y_test)))
print('==========================')
print("随机森林训练数据得分:{:.2f}".format(forest.score(X_test, y_test)))
#画出决策树的执行图
dot_data = StringIO()
dot_data = export_graphviz(clf, out_file=None, class_names=list(data_dummie.columns),
feature_names=list(data_dummie.columns)[:-2], impurity=False, filled=True)
graph = graphviz.Source(dot_data) # doctest: +SKIP
#在同级目录下生成tree.pdf文件
graph.render("Datingtree") # 保存成pdf
#对Mr Z男士进行预测(年龄37,在省机关工作,硕士学历等等)
Mr_z = [[37, 40, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
dating_desc = clf.predict(Mr_z)
dating_desc1 = forest.predict(Mr_z)
print('决策树预测结果为:')
print('==========================')
if dating_desc ==1 :
print("金龟婿啊,这哥们月薪超过5万了,快去约会")
else:
print("算了,不满足你的要求")
print('\n')
print('随机森林预测结果为:')
print('==========================')
if dating_desc ==1 :
print("金龟婿啊,这哥们月薪超过5万了,快去约会")
else:
print("算了,不满足你的要求")
执行结果如下:
>>>>>>>>>>>原始数据前5行
年龄 单位性质 学历 性别 周工作时长 职业 \
0 39 State-gov Bachelors Male 40 Adm-clerical
1 50 Self-emp-not-inc Bachelors Male 13 Exec-managerial
2 38 Private HS-grad Male 40 Handlers-cleaners
3 53 Private 11th Male 40 Handlers-cleaners
4 28 Private Bachelors Female 40 Prof-specialty
收入
0 <=50K
1 <=50K
2 <=50K
3 <=50K
4 <=50K
样本原始特征:
['年龄', '单位性质', '学历', '性别', '周工作时长', '职业', '收入']
虚拟变量特征:
['年龄', '周工作时长', '单位性质_ ?', '单位性质_ Federal-gov', '单位性质_ Local-gov', '单位性质_ Never-worked', '单位性质_ Private', '单位性质_ Self-emp-inc', '单位性质_ Self-emp-not-inc', '单位性质_ State-gov', '单位性质_ Without-pay', '学历_ 10th', '学历_ 11th', '学历_ 12th', '学历_ 1st-4th', '学历_ 5th-6th', '学历_ 7th-8th', '学历_ 9th', '学历_ Assoc-acdm', '学历_ Assoc-voc', '学历_ Bachelors', '学历_ Doctorate', '学历_ HS-grad', '学历_ Masters', '学历_ Preschool', '学历_ Prof-school', '学历_ Some-college', '性别_ Female', '性别_ Male', '职业_ ?', '职业_ Adm-clerical', '职业_ Armed-Forces', '职业_ Craft-repair', '职业_ Exec-managerial', '职业_ Farming-fishing', '职业_ Handlers-cleaners', '职业_ Machine-op-inspct', '职业_ Other-service', '职业_ Priv-house-serv', '职业_ Prof-specialty', '职业_ Protective-serv', '职业_ Sales', '职业_ Tech-support', '职业_ Transport-moving', '收入_ <=50K', '收入_ >50K']
['年龄', '周工作时长', '单位性质_ ?', '单位性质_ Federal-gov', '单位性质_ Local-gov', '单位性质_ Never-worked', '单位性质_ Private', '单位性质_ Self-emp-inc', '单位性质_ Self-emp-not-inc', '单位性质_ State-gov', '单位性质_ Without-pay', '学历_ 10th', '学历_ 11th', '学历_ 12th', '学历_ 1st-4th', '学历_ 5th-6th', '学历_ 7th-8th', '学历_ 9th', '学历_ Assoc-acdm', '学历_ Assoc-voc', '学历_ Bachelors', '学历_ Doctorate', '学历_ HS-grad', '学历_ Masters', '学历_ Preschool', '学历_ Prof-school', '学历_ Some-college', '性别_ Female', '性别_ Male', '职业_ ?', '职业_ Adm-clerical', '职业_ Armed-Forces', '职业_ Craft-repair', '职业_ Exec-managerial', '职业_ Farming-fishing', '职业_ Handlers-cleaners', '职业_ Machine-op-inspct', '职业_ Other-service', '职业_ Priv-house-serv', '职业_ Prof-specialty', '职业_ Protective-serv', '职业_ Sales', '职业_ Tech-support', '职业_ Transport-moving']
>>>>>>>>>>>get_dummies 处理后数据前5行
年龄 周工作时长 单位性质_ ? 单位性质_ Federal-gov 单位性质_ Local-gov 单位性质_ Never-worked \
0 39 40 0 0 0 0
1 50 13 0 0 0 0
2 38 40 0 0 0 0
3 53 40 0 0 0 0
4 28 40 0 0 0 0
单位性质_ Private 单位性质_ Self-emp-inc 单位性质_ Self-emp-not-inc 单位性质_ State-gov \
0 0 0 0 1
1 0 0 1 0
2 1 0 0 0
3 1 0 0 0
4 1 0 0 0
... 职业_ Machine-op-inspct 职业_ Other-service 职业_ Priv-house-serv \
0 ... 0 0 0
1 ... 0 0 0
2 ... 0 0 0
3 ... 0 0 0
4 ... 0 0 0
职业_ Prof-specialty 职业_ Protective-serv 职业_ Sales 职业_ Tech-support \
0 0 0 0 0
1 0 0 0 0
2 0 0 0 0
3 0 0 0 0
4 1 0 0 0
职业_ Transport-moving 收入_ <=50K 收入_ >50K
0 0 1 0
1 0 1 0
2 0 1 0
3 0 1 0
4 0 1 0
[5 rows x 46 columns]
代码运行结果为:
==========================
决策树训练数据得分:0.79
==========================
随机森林训练数据得分:0.78
决策树预测结果为:
==========================
算了,不满足你的要求
随机森林预测结果为:
==========================
算了,不满足你的要求
注释:
画决策树的图的时候出现了中文乱码的情况,参考这两位大哥的帖子修改
《window系统sklearn决策树graphviz绘图中文乱码解决方法》
《Graphviz画决策树中文乱码解决》
三、随机森林的优势和不足
优势:
- 1.由于对每个特征进行单独处理,因此并不需要对数据进行转换,几乎不需要对数据进行预处理
- 2.支持并行处理,用 n_jobs 参数来调节。当n_jobs = -1时,随机森林会使用CPU的全部内核。
- 3.随机森林生成每颗决策树的方法是随机的,如果不希望建模的结果太过于不稳定的话,要固化 random_state参数
不足: - 对于高维数据集、稀疏数据集来说,线性模型比随机森林的表现要好
- 随机森林系相对更消耗内存,速度也比线性模型慢,如果希望节省内存和时间的话,建议选择线性模型