在解释随机森林前,需要先提一下决策树。决策树是一种很简单的算法,他的解释性强,也符合人类的直观思维。这是一种基于if-then-else规则的有监督学习算法,下面的图片可以直观的表达决策树的逻辑。(1条消息) 【机器学习算法复现】决策树,树形结构解决属性选择问题,一种可回归可分类的有监督学习算法_羞儿的博客-CSDN博客
随机森林 – Random Forest | RF,随机森林是由很多决策树构成的,不同决策树之间没有关联。
当我们进行分类任务时,新的输入样本进入,就让森林中的每一棵决策树分别进行判断和分类,每个决策树会得到一个自己的分类结果,决策树的分类结果中哪一个分类最多,那么随机森林就会把这个结果当做最终的结果。
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_split=1e-07,bootstrap=True,
oob_score=False, n_jobs=1,
random_state=None, verbose=0,
warm_start=False, class_weight=None)
RF划分时考虑的最大特征数 max_features: 就是之前提到的“在每个节点处,从M中随机选择m个特征维度”中的那个m。默认是"auto",意味着每个节点在划分时随机考虑 N \sqrt{N} N 个特征;如果是"log2"意味着划分时随机考虑 l o g 2 N log_2^N log2N 个特征;如果是整数,代表考虑的特征绝对数。如果是浮点数,代表考虑特征百分比,即考虑百分比*总特征维度数取整后的特征数。一般用默认的"auto"就可以了;如果特征数非常多,可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间。
决策树最大深度max_depth: 默认可以不输入,如果不输入的话,决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间。
内部节点再划分所需最小样本数min_samples_split: 这个值限制了子树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再划分。默认是2。如果样本量数量级非常大,则推荐增大这个值。
叶子节点最少样本数min_samples_leaf: 这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝,只保留原来的父节点。默认是1。如果样本量数量级非常大,则推荐增大这个值。
叶子节点最小的样本权重和min_weight_fraction_leaf:这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝,只保留原来的父节点。 默认是0,就是不考虑权重问题。如果我们有较多样本有缺失值,或者分类树样本的分布类别非常不平衡,就会引入样本权重,这时我们就要注意这个值了。
最大叶子节点数max_leaf_nodes: 通过限制最大叶子节点数,可以防止过拟合,默认是"None”,即不限制最大的叶子节点数。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征非常多的话,可以加以限制,具体的值可以通过交叉验证得到。
节点划分最小不纯度min_impurity_split: 这个值限制了决策树的增长,如果某节点的不纯度(基于基尼系数,均方差)小于这个阈值,则该节点不再生成子节点。即为叶子节点 。一般不推荐改动,默认值1e-7。
导包,加载数据
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
import numpy as np
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt
iris = datasets.load_iris()
print(iris['data'].shape, iris['target'].shape) # (150, 4) (150,)
X = iris.data[:,[2,3]]
y = iris.target
print('Class labels:', np.unique(y))
# 划分数据集为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1, stratify=y)
print(X_train.shape, y_train.shape)
(150, 4) (150,)
Class labels: [0 1 2]
(105, 2) (105,)
训练,并绘制分类决策边界:
def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):
# setup marker generator and color map
markers = ('s', 'x', 'o', '^', 'v')
colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
cmap = ListedColormap(colors[:len(np.unique(y))])
# plot the decision surface
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
np.arange(x2_min, x2_max, resolution))
Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)
plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=cmap)
plt.xlim(xx1.min(), xx1.max())
plt.ylim(xx2.min(), xx2.max())
for idx, cl in enumerate(np.unique(y)):
plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],alpha=0.8, c=colors[idx], marker=markers[idx], label=cl,)
# highlight test samples
if test_idx:
# plot all samples
X_test, y_test = X[test_idx, :], y[test_idx]
plt.scatter(X_test[:, 0], X_test[:, 1],
edgecolor='black', alpha=1.0,
linewidth=1, marker='o',
s=100, label='test set')
forest = RandomForestClassifier(criterion='gini', # 划分准则
n_estimators=25, # 25个基学习器(决策树)
random_state=1,
n_jobs=2) # 并行执行
forest.fit(X_train, y_train)
X_combined = np.vstack((X_train, X_test))
y_combined = np.hstack((y_train, y_test))
plot_decision_regions(X_combined, y_combined, classifier=forest, test_idx=range(105,150))
plt.xlabel('petal length')
plt.ylabel('petal width')
plt.legend(loc='upper left')
plt.show()
随机森林-特征重要性
使用随机森林获得特征重要性,数据集:白酒数据,共有13个特征,使用RandomForestClassifier训练,然后调用feature_importances_属性获得特征重要性:
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
data_dir = './data/'
# Wine dataset and rank the 13 features by their respective importance measures
df_wine = pd.read_csv(data_dir+'wine.data', header=None,
names=['Class label', 'Alcohol', 'Malic acid', 'Ash', 'Alcalinity of ash', 'Magnesium',
'Total phenols', 'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins', 'Color intensity',
'Hue', 'OD280/OD315 of diluted wines', 'Proline'])
print('Class labels', np.unique(df_wine['Class label']))
print('numbers of features:', len(df_wine.keys())-1)
df_wine.head()
计算重要特征
# 划分训练集测试集
X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0, stratify=y)
print(X_train.shape)
feat_labels = df_wine.columns[1:]
forest = RandomForestClassifier(n_estimators=200, random_state=1) # 实例化随机森林
forest.fit(X_train, y_train)
importances = forest.feature_importances_
print(len(importances))
print(importances)
"""
numpy.argsort(a, axis=-1, kind=’quicksort’, order=None)
功能: 将矩阵a在指定轴axis上排序,并返回排序后的下标
参数: a:输入矩阵, axis:需要排序的维度
返回值: 输出排序后的下标
"""
indices = np.argsort(importances)[::-1] # 取反后是从大到小
print(indices)
for i in range(X_train.shape[1]):
print("%2d) %-*s %f" % (i + 1, 30, feat_labels[indices[i]], importances[indices[i]]))
(124, 13)
13
[0.11535953 0.02485979 0.01367936 0.0206145 0.03254997 0.04019533
0.18793917 0.01096301 0.02611948 0.13488692 0.06345939 0.13440744
0.19496612]
[12 6 9 11 0 10 5 4 8 1 3 2 7]
1) Proline 0.194966
2) Flavanoids 0.187939
3) Color intensity 0.134887
4) OD280/OD315 of diluted wines 0.134407
5) Alcohol 0.115360
6) Hue 0.063459
7) Total phenols 0.040195
8) Magnesium 0.032550
9) Proanthocyanins 0.026119
10) Malic acid 0.024860
11) Alcalinity of ash 0.020615
12) Ash 0.013679
13) Nonflavanoid phenols 0.010963
随机森林算法(RandomForest)的输出有一个变量是 feature_importances_ ,翻译过来是 特征重要性,RF可以输出两种 feature_importance,分别是Variable importance和Gini importance,两者都是feature_importance,只是计算方法不同。
Variable importance :选定一个feature M,在所有OOB样本的feature M上人为添加噪声,再测试模型在OOB上的判断精确率,精确率相比没有噪声时下降了多少,就表示该特征有多重要。假如一个feature对数据分类很重要,那么一旦这个特征的数据不再准确,对测试结果会造成较大的影响,而那些不重要的feature,即使受到噪声干扰,对测试结果也没什么影响。这就是 Variable importance 方法的朴素思想。
Gini importance : 选定一个feature M,统计RF的每一棵树中,由M形成的分支节点的Gini指数下降程度(或不纯度下降程度)之和,这就是M的importance。两者对比来看,前者比后者计算量更大,后者只需要一边构建DT,一边做统计就可以。从sklearn的官方文档对feature_importances_参数的描述来看,sklearn应当是使用了Gini importance对feature进行排序,同时sklearn把所有的Gini importance以sum的方式做了归一化,得到了最终的feature_importances_输出参数。
plt.title('Feature Importance')
plt.bar(range(X_train.shape[1]), importances[indices], align='center')
plt.xticks(range(X_train.shape[1]), feat_labels[indices], rotation=90)
plt.xlim([-1, X_train.shape[1]])
plt.tight_layout()
plt.show()
随机森林-回归任务
数据集:房价预测,导包加载数据。
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error
df = pd.read_csv('./data/housing.data.txt',header=None,sep='\s+',
names= ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV'])
df.head()
数据集划分及训练预测,回归树的评价指标scikit-learn/_criterion.pyx at main · scikit-learn/scikit-learn (github.com)
# 划分数据集
X = df.iloc[:, :-1].values
y = df['MEDV'].values
X_train, X_test, y_train, y_test =train_test_split(X, y, test_size=0.2, random_state=1)
print(X_train.shape, y_train.shape)
# The 'criterion' parameter of RandomForestRegressor must be a str among {'friedman_mse', 'poisson', 'absolute_error', 'squared_error'}.
forest = RandomForestRegressor(n_estimators=100, criterion='friedman_mse', random_state=1, n_jobs=-1)
forest.fit(X_train, y_train) # 训练
y_train_pred = forest.predict(X_train)
y_test_pred = forest.predict(X_test)
print(len(y_train_pred))
print(len(y_test_pred))
print('friedman_mse train: %.3f, test: %.3f' % (mean_squared_error(y_train, y_train_pred), mean_squared_error(y_test, y_test_pred)))
(404, 13) (404,)
404
102
friedman_mse train: 1.254, test: 8.657
推荐的GPU平台
colab(推荐使用,需要VPN,免费GPU):https://colab.research.google.com/
矩阵云:https://matpool.com/
极客云:https://www.jikecloud.net/
DBC:https://www.dbchain.ai/home
极链云:https://cloud.videojj.com/store
Featurize:https://featurize.cn/
openbayes:https://openbayes.com/
MistGPU:https://mistgpu.com/