Python机器学习之随机森林

引言

 随机森林的原理网上有一大堆,作为入门小白,下面来根据教材敲两个随机森林的代码。
随机森林有两个比较重要的参数: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()

运行结果如下图可示,随机森林的分类比较细腻,可调节参数查看分类器的表现


6.3RadomForest.png

二、要不要和相亲对象进一步发展

采用美国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("算了,不满足你的要求")

执行结果如下:


6.4DexisionAndRadomForest.png
>>>>>>>>>>>原始数据前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参数
    不足:
  • 对于高维数据集、稀疏数据集来说,线性模型比随机森林的表现要好
  • 随机森林系相对更消耗内存,速度也比线性模型慢,如果希望节省内存和时间的话,建议选择线性模型
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,312评论 5 473
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,578评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,337评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,134评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,161评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,303评论 1 280
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,761评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,421评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,609评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,450评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,504评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,194评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,760评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,836评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,066评论 1 257
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,612评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,178评论 2 341