我为什么写这篇博客?
答:记录一下自己对于sklearn库的学习过程以及学习方法,方便以后进行复用
这篇文章主要讲什么?
这篇文章是我使用sklearn的随机森林对我这个你在研究的数据进行处理分析的一个过程,其中包括对应的一些方法,具体见目录。
随机森林简介?
随机森林是一种统计学习理论,其随机有两个方面:首先在训练的每一轮中,都是对原始样本集有放回的抽取固定数目的样本点,形成k 个互不相同的样本集。第二个点是:对于每一个决策树的建立是从总的属性中随机抽取一定量的属性作为分裂属性集,这样对于k个树分类器均是不相同的。由随机生成的k个决策树组成了随机森林。
对于每一个决策树来说,其分裂属性是不断地选取具有最大信息增益的属性进行排列。整个随机森林建立后,最终的分类标准采用投票机制得到可能性最高的结果。
sklearn.ensemble.RandomForestRegressor (
n_estimators=’warn’, # 迭代次数,即森林中决策树的数量
criterion=’mse’, # 分裂节点所用的标准,可选“gini”, “entropy”,默认“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, # 最大叶子节点数,整数,默认为None
min_impurity_decrease=0.0, # 如果分裂指标的减少量大于该值,则进行分裂。
min_impurity_split=None, # 决策树生长的最小纯净度。不推荐使用
bootstrap=True, # 是否有放回的随机选取样本
oob_score=False, # 是否采用袋外样本来评估模型的好坏。建议True
n_jobs=None, # 并行计算数。默认是None。一般选择-1,根据计算机核数自动选择
random_state=None, # 控制bootstrap的随机性以及选择样本的随机性。一般数字是一样的,便于调参
verbose=0, # 在拟合和预测时控制详细程度。默认是0。
warm_start=False # 若设为True则可以再次使用训练好的模型并向其中添加更多的基学习器
)
所有的参数,属性与接口,全部和随机森林分类器一致。仅有的不同就是回归树与分类树的不同,不纯度的指标,参数Criterion不一致。
RF框架特征
n_estimators: 也就是弱学习器的最大迭代次数,或者说最大的弱学习器的个数。一般来说n_estimators太小,容易欠拟合,n_estimators太大,计算量会太大,并且n_estimators到一定的数量后,再增大n_estimators获得的模型提升会很小,所以一般选择一个适中的数值。默认是100。
oob_score即是否采用袋外样本来评估模型的好坏。默认识False。个人推荐设置为True,因为袋外分数反应了一个模型拟合后的泛化能力。
criterion: 即CART树做划分时对特征的评价标准。分类模型和回归模型的损失函数是不一样的。分类RF对应的CART分类树默认是基尼系数gini,另一个可选择的标准是信息增益。回归RF对应的CART回归树默认是均方差mse,另一个可以选择的标准是绝对值差mae。一般来说选择默认的标准就已经很好的。
RF决策树参数
RF划分时考虑的最大特征数max_features: 可以使用很多种类型的值,默认是"auto",意味着划分时最多考虑 N \sqrt{N} N个特征;如果是"log2"意味着划分时最多考虑 l o g 2 N log_2N log2N个特征;如果是"sqrt"或者"auto"意味着划分时最多考虑 N \sqrt{N} N个特征。如果是整数,代表考虑的特征绝对数。如果是浮点数,代表考虑特征百分比,即考虑(百分比xN)取整后的特征数。其中N为样本总特征数。一般我们用默认的"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。
random——state:这里的random_state就是为了保证程序每次运行都分割一样的训练集和测试集。否则,同样的算法模型在不同的训练集和测试集上的效果不一样。
上面决策树参数中最重要的包括最大特征数max_features, 最大深度max_depth, 内部节点再划分所需最小样本数min_samples_split和叶子节点最少样本数min_samples_leaf。
调参链接参考
本数据使用的是经过处理出租车轨迹数据,共有15万条数据。
特征:
标签:
RG:RelativeGap
df = pd.read_csv(r'traval_merge_rp_od20_dis4000CV_cro_road.txt',sep='\t',encoding='gbk')
df = df.dropna(axis=0, how='any') # 将缺失值的行丢弃
col = ['最短行驶路程','OD_speed','OD_speedcv','备选路径数','OD_distancecv','crossroadcv','speed','speedcv','mean_crossroad']
#取得特征
X = df[col].values
#取得标签
Y = df.loc[:,'RG'].values
#进行数据集划分,70%作为训练, 30作为测试
x_train,x_test,y_train,y_test = train_test_split(X, Y, test_size=0.3)
#利用随机森林进行训练
forest = RandomForestRegressor(
n_estimators=1000,
random_state=1,
n_jobs=-1)
forest.fit(x_train,y_train)
#
score = forest.score(x_test, y_test)
result = forest.predict(x_test)
plt.figure()
#只取前一百条可视化,因为数据太多了
plt.plot(np.arange(100), y_test[:100], "go-", label="True value")
plt.plot(np.arange(100), result[:100], "ro-", label="Predict value")
plt.title(f"RandomForest---score:{score}")
plt.legend(loc="best")
plt.show()
# 下面对训练好的随机森林,完成重要性评估
# feature_importances_ 可以调取关于特征重要程度
importances = forest.feature_importances_
print("重要性:", importances)
x_columns = ['OD_distance','OD_speed','OD_speedcv','route_num','OD_distancecv','crossroadcv','speed','speedcv','mean_crossroad']
#返回数组从大到小的索引值
indices = np.argsort(importances)[::-1]
for f in range(x_train.shape[1]):
# 对于最后需要逆序排序,我认为是做了类似决策树回溯的取值,从叶子收敛
# 到根,根部重要程度高于叶子。
print("%2d) %-*s %f" % (f + 1, 30, col[indices[f]], importances[indices[f]]))
# 筛选变量(选择重要性比较高的变量)
threshold = 0.15
x_selected = x_train[:, importances > threshold]
# 可视化
plt.figure(figsize=(10, 6))
plt.title("importance of feature in dateset", fontsize=18)
plt.ylabel("import level", fontsize=15, rotation=90)
x_columns1 = [x_columns[i] for i in indices]
for i in range(len(x_columns)):
plt.bar(i, importances[indices[i]], color='orange', align='center')
plt.xticks(np.arange(len(x_columns)), x_columns1, fontsize=10, rotation =30)
plt.show()
#判断是否有空值
def jud_array(x):
print(np.isnan(x).any())
#traval_merge_rp_od20_dis4000CV_cro_road.txt
df = pd.read_csv(r'traval_merge_rp_od20_dis4000CV_cro_road.txt',sep='\t',encoding='gbk')
df = df.dropna(axis=0, how='any')
col = ['最短行驶路程','OD_speed','OD_speedcv','备选路径数','OD_distancecv','crossroadcv','speed','speedcv','mean_crossroad']
X = df[col]
#取得特征
X = df[col].values
#取得标签
Y = df.loc[:,'RG'].values
#进行数据集划分
x_train,x_test,y_train,y_test = train_test_split(X, Y, test_size=0.3)
#利用随机森林进行训练
forest = RandomForestRegressor(
n_estimators=100,
random_state=1,
n_jobs=-1)
forest.fit(x_train,y_train)
#预测结果可视化
score = forest.score(x_test, y_test)
result = forest.predict(x_test)
plt.figure()
plt.plot(np.arange(100), y_test[:100], "go-", label="True value")
plt.plot(np.arange(100), result[:100], "ro-", label="Predict value")
plt.title(f"RandomForest---score:{score}")
plt.legend(loc="best")
plt.show()
# 分数
y_pred = forest.predict(x_test)
# 下面对训练好的随机森林,完成重要性评估
# feature_importances_ 可以调取关于特征重要程度
importances = forest.feature_importances_
print("重要性:", importances)
x_columns = ['OD_distance','OD_speed','OD_speedcv','route_num','OD_distancecv','crossroadcv','speed','speedcv','mean_crossroad']
# 返回数组从大到小的索引值
indices = np.argsort(importances)[::-1]
for f in range(x_train.shape[1]):
# 对于最后需要逆序排序,我认为是做了类似决策树回溯的取值,从叶子收敛
# 到根,根部重要程度高于叶子。
print("%2d) %-*s %f" % (f + 1, 30, col[indices[f]], importances[indices[f]]))
# 筛选变量(选择重要性比较高的变量)
threshold = 0.15
x_selected = x_train[:, importances > threshold]
# 可视化
plt.figure(figsize=(10, 6))
plt.title("importance of feature in dateset", fontsize=18)
plt.ylabel("import level", fontsize=15, rotation=90)
x_columns1 = [x_columns[i] for i in indices]
for i in range(len(x_columns)):
plt.bar(i, importances[indices[i]], color='orange', align='center')
plt.xticks(np.arange(len(x_columns)), x_columns1, fontsize=10, rotation=30)
plt.show()
目前这个博客还不够完善,后续我会继续添加缺失值处理以及调参过程。