随机森林算法&python应用
随机森林算法
决策树算法可以很容易的将模型进行可视化,同时它是将每个样本特征进行单独处理,故而不需要的对数据进行转换。但是决策树会很容易出现过拟合,为了避免过拟合现象,可以使用集合学习的方法,像:随机森林算法。
随机森林又被称为:随机决策森林,是一种集合学习方法(参见下图),既可以用于分类,也可以用作回归。分类:在森林内部会进行“投票”,每棵树预测出数据类别的概率,随机森林会把这些概率值求平均,让后将样本放入概率最大的分类中。回归:随机森林会把所有决策树预测的值取平均数。
随机森林算法之所以可以解决过拟合问题:因为随机森林是把不同的几棵决策树打包到一起,每棵树的参数都不相同,然后我们把每棵树预测的结果取平均值,这样不仅可以保留决策树工作的高效,又可以降低过拟合的风险。
随机森林算法可以大致分为两个步骤:第一,创建决策树,第二,根据第一步中决策树的分类器结果做出预测。随机森林算法与决策树算法之间的区别是:前者查找根节点和分割特征节点的过程是随机进行的。
- 构建过程:
(1)数据的随机选取,若训练集中有个样本,又放回的随机抽取个。这个样本就作为生成该决策树的训练集。
(2)特征的随机选取,对于每个样本,如果有个输入变量(特征),指定一个常数,然后随机的从中选取个最优的分裂特征开分裂节点。
- 预测过程:
(1)使用每一个随机创建的决策树的规则来测试特征的结果(标签)
(2)计算每个预测目标的票数
(3)获得票数最高的结果将作为随机森林算法的最终预测。
注:随机森林算法也不要求对数据进行预处理,同时支持并行处理。此外,随机森林生成每一棵决策树的方法是随机的,则不同的random_state参数会导致模型完全不同,所以为了模型的相对稳定,要固化random_state这个参数的值。但是!!!随机森林,对于高维数据集、稀疏数据集来说,很不适应。
构建决策树
author by xiaoyao
# 导入libraries
import numpy as np
# 导入画图工具
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
# 导入tree模型和数据集加载工具
from sklearn import datasets
from sklearn.ensemble import RandomForestClassifier
# 导入数据集拆分工具
from sklearn.model_selection import train_test_split
wine = datasets.load_wine()
# 这里只选取数据集的前两个特征
X = wine.data[:,:2]
y = wine.target
# 将数据集划分为训练集个测试集
X_train, X_test, y_train, y_test = train_test_split(X, y)
# 忽略警告
import warnings
warnings.filterwarnings("ignore")
# 暂时设定随机森林中有6棵树
forest = RandomForestClassifier(n_estimators=6, random_state=3)
# 使用模型拟合数据
forest.fit(X_train, y_train)
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
max_depth=None, max_features='auto', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=6,
n_jobs=None, oob_score=False, random_state=3, verbose=0,
warm_start=False)
其中,bootstrap参数:代表的是bootstrap sample。也就是又放回抽样,bootstrap生成的数据集和原始数据集在数据量上是一致的,但由于进行了重复采样,因此其中有一些数据点会丢失。通过重新生成数据集,可以让随机森林中的每一棵决策树在构建的时候,彼此之间有差异。max_features的取值越高,随机森林中的每一棵树就会"越相似",从而因为有更多的不同特征值可以取,也就会更容易取拟合数据。
# 定义图像中分区的颜色和散点的颜色
cmap_light = ListedColormap(["#FFAAAA", "#AAFFAA", "#AAAAFF"])
cmap_bold = ListedColormap(["#FF0000", "#00FF00", "#0000FF"])
# 分别用样本的两个特征值创建图像和横轴、纵轴
x_min, x_max = X_train[:,0].min() - 1, X_train[:,0].max() + 1
y_min, y_max = X_train[:,1].min() - 1, X_train[:,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()])
# 给每个分类中的样本分配不同的颜色
z = z.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx, yy, z, cmap=cmap_light)
# 使用散点图进行表示
plt.scatter(X[:,0], X[:,1], c=y, cmap=cmap_bold, edgecolor="k",s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("Classifier:(max_depth = 3)")
plt.show()
随机森林实例
author by xiaoyao
# 导入相应的libraries
import pandas as pd
from sklearn import tree
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
# 忽略警告
import warnings
warnings.filterwarnings("ignore")
# 导入数据集,数据集下载地址:http://archive.ics.uci.edu/ml/machine-learning-databases/adult/
# 原始数据无列名(属性名)
data = pd.read_csv("./datasets/adult.csv", header=None,index_col=False,
names=['年龄','单位性质','权重','学历','受教育时常',
'婚姻状况','职业','家庭情况','种族','性别',
'资产所得','资产损失','周工作时长','原籍','收入'])
data.head()
年龄 | 单位性质 | 权重 | 学历 | 受教育时常 | 婚姻状况 | 职业 | 家庭情况 | 种族 | 性别 | 资产所得 | 资产损失 | 周工作时长 | 原籍 | 收入 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 39 | State-gov | 77516 | Bachelors | 13 | Never-married | Adm-clerical | Not-in-family | White | Male | 2174 | 0 | 40 | United-States | <=50K |
1 | 50 | Self-emp-not-inc | 83311 | Bachelors | 13 | Married-civ-spouse | Exec-managerial | Husband | White | Male | 0 | 0 | 13 | United-States | <=50K |
2 | 38 | Private | 215646 | HS-grad | 9 | Divorced | Handlers-cleaners | Not-in-family | White | Male | 0 | 0 | 40 | United-States | <=50K |
3 | 53 | Private | 234721 | 11th | 7 | Married-civ-spouse | Handlers-cleaners | Husband | Black | Male | 0 | 0 | 40 | United-States | <=50K |
4 | 28 | Private | 338409 | Bachelors | 13 | Married-civ-spouse | Prof-specialty | Wife | Black | Female | 0 | 0 | 40 | Cuba | <=50K |
import pandas_profiling
rep = pandas_profiling.ProfileReport(data)
# 将生成的数据分析报告保存至本地html文件
rep.to_file("./rep.html")
报告具体形式:
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 32561 entries, 0 to 32560
Data columns (total 15 columns):
年龄 32561 non-null int64
单位性质 32561 non-null object
权重 32561 non-null int64
学历 32561 non-null object
受教育时常 32561 non-null int64
婚姻状况 32561 non-null object
职业 32561 non-null object
家庭情况 32561 non-null object
种族 32561 non-null object
性别 32561 non-null object
资产所得 32561 non-null int64
资产损失 32561 non-null int64
周工作时长 32561 non-null int64
原籍 32561 non-null object
收入 32561 non-null object
dtypes: int64(6), object(9)
memory usage: 3.7+ MB
可以看到在数据集中,很多的列取值都是字符串,不方便进行建模。我将其处理为:整型数值,操作如下:
# 使用get_dummies将文本数据转化为数值
data_dummies = pd.get_dummies(data)
# 分别输出原始特征和处理之后的特征
print("原始特征:",(data.columns))
print("处理后的特征:",(data_dummies.columns))
原始特征: Index(['年龄', '单位性质', '权重', '学历', '受教育时常', '婚姻状况', '职业', '家庭情况', '种族', '性别',
'资产所得', '资产损失', '周工作时长', '原籍', '收入'],
dtype='object')
处理后的特征: Index(['年龄', '权重', '受教育时常', '资产所得', '资产损失', '周工作时长', '单位性质_ ?',
'单位性质_ Federal-gov', '单位性质_ Local-gov', '单位性质_ Never-worked',
...
'原籍_ Scotland', '原籍_ South', '原籍_ *', '原籍_ Thailand',
'原籍_ Trinadad&Tobago', '原籍_ United-States', '原籍_ Vietnam',
'原籍_ Yugoslavia', '收入_ <=50K', '收入_ >50K'],
dtype='object', length=110)
data.head()
年龄 | 单位性质 | 权重 | 学历 | 受教育时常 | 婚姻状况 | 职业 | 家庭情况 | 种族 | 性别 | 资产所得 | 资产损失 | 周工作时长 | 原籍 | 收入 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 39 | State-gov | 77516 | Bachelors | 13 | Never-married | Adm-clerical | Not-in-family | White | Male | 2174 | 0 | 40 | United-States | <=50K |
1 | 50 | Self-emp-not-inc | 83311 | Bachelors | 13 | Married-civ-spouse | Exec-managerial | Husband | White | Male | 0 | 0 | 13 | United-States | <=50K |
2 | 38 | Private | 215646 | HS-grad | 9 | Divorced | Handlers-cleaners | Not-in-family | White | Male | 0 | 0 | 40 | United-States | <=50K |
3 | 53 | Private | 234721 | 11th | 7 | Married-civ-spouse | Handlers-cleaners | Husband | Black | Male | 0 | 0 | 40 | United-States | <=50K |
4 | 28 | Private | 338409 | Bachelors | 13 | Married-civ-spouse | Prof-specialty | Wife | Black | Female | 0 | 0 | 40 | Cuba | <=50K |
data_dummies.head()
年龄 | 权重 | 受教育时常 | 资产所得 | 资产损失 | 周工作时长 | 单位性质_ ? | 单位性质_ Federal-gov | 单位性质_ Local-gov | 单位性质_ Never-worked | ... | 原籍_ Scotland | 原籍_ South | 原籍_ * | 原籍_ Thailand | 原籍_ Trinadad&Tobago | 原籍_ United-States | 原籍_ Vietnam | 原籍_ Yugoslavia | 收入_ <=50K | 收入_ >50K | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 39 | 77516 | 13 | 2174 | 0 | 40 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
1 | 50 | 83311 | 13 | 0 | 0 | 13 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
2 | 38 | 215646 | 9 | 0 | 0 | 40 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
3 | 53 | 234721 | 7 | 0 | 0 | 40 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
4 | 28 | 338409 | 13 | 0 | 0 | 40 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
5 rows × 110 columns
将各列分配给特征向量和分类标签
# 定义数据集的特征值
features = data_dummies.loc[:, '年龄':'原籍_ Yugoslavia']
X = features.values
# 将收入大于50k作为预测的目标
y = data_dummies['收入_ >50K'].values
# 输出特征与标签的形态
print("特征形态:{} 标签形态:{}".format(X.shape, y.shape))
特征形态:(32561, 108) 标签形态:(32561,)
# 先使用决策数模型进行预测
# 将数据拆分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 1)
# 设最大深度为5
dt_tree =tree.DecisionTreeClassifier(max_depth=5)
dt_tree.fit(X_train, y_train)
dt_tree.score(X_test, y_test)
0.8550546615894853
# 使用交叉验证,平均水平依然接近上面的
from sklearn.model_selection import cross_val_score
scores = cross_val_score(dt_tree, X, y, cv=20,scoring='accuracy')
print(scores)
print(scores.mean())
[0.83977901 0.84275184 0.8482801 0.84336609 0.85012285 0.8531941
0.82555283 0.84398034 0.8458231 0.85380835 0.85995086 0.83783784
0.85257985 0.84889435 0.86425061 0.85257985 0.8507371 0.86302211
0.84766585 0.84643735]
0.8485307193180122
# 使用随机森林算法
forest = RandomForestClassifier(n_estimators = 5,random_state=0)
forest.fit(X_train, y_train)
forest.score(X_test, y_test)
0.8431396634320109
# 使用交叉验证
scores = cross_val_score(forest, X, y,cv=5,scoring='accuracy')
print(scores)
print(scores.mean())
[0.82320442 0.83968059 0.83230958 0.84336609 0.82862408 0.85012285
0.82678133 0.8458231 0.84336609 0.83108108 0.83722359 0.83046683
0.84336609 0.83599509 0.8482801 0.84213759 0.84766585 0.85257985
0.83169533 0.84459459]
0.8389182062524604