机器学习第一步,这是一篇手把手的随机森林入门实战

本文主要是介绍机器学习第一步,这是一篇手把手的随机森林入门实战,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

选自TowardsDataScience 作者:Alexander Cheng 机器之心编译 参与:高璇、思

到了 2020 年,我们已经能找到很多好玩的机器学习教程。本文则从最流行的随机森林出发,手把手教你构建一个模型,它的完整流程到底是什么样的。


作为数据科学家,我们可以通过很多方法来创建分类模型。最受欢迎的方法之一是随机森林。我们可以在随机森林上调整超参数来优化模型的性能。

在用模型拟合之前,尝试主成分分析(PCA)也是常见的做法。但是,为什么还要增加这一步呢?难道随机森林的目的不是帮助我们更轻松地理解特征重要性吗?

当我们分析随机森林模型的「特征重要性」时,PCA 会使每个「特征」的解释变得更加困难。但是 PCA 会进行降维操作,这可以减少随机森林要处理的特征数量,因此 PCA 可能有助于加快随机森林模型的训练速度。

请注意,计算成本高是随机森林的最大缺点之一(运行模型可能需要很长时间)。尤其是当你使用数百甚至上千个预测特征时,PCA 就变得非常重要。因此,如果只想简单地拥有最佳性能的模型,并且可以牺牲解释特征的重要性,那么 PCA 可能会很有用。

现在让我们举个例子。我们将使用 Scikit-learn 的「乳腺癌」数据集,并创建 3 个模型,比较它们的性能:

 1. 随机森林

2. 具有 PCA 降维的随机森林

3. 具有 PCA 降维和超参数调整的随机森林

导入数据

首先,我们加载数据并创建一个 DataFrame。这是 Scikit-learn 预先清理的「toy」数据集,因此我们可以继续快速建模。但是,作为最佳实践,我们应该执行以下操作:

  • 使用 df.head()查看新的 DataFrame,以确保它符合预期。

  • 使用 df.info()可以了解每一列中的数据类型和数据量。可能需要根据需要转换数据类型。

  • 使用 df.isna()确保没有 NaN 值。可能需要根据需要处理缺失值或删除行。

  • 使用 df.describe()可以了解每列的最小值、最大值、均值、中位数、标准差和四分位数范围。

名为「cancer」的列是我们要使用模型预测的目标变量。「0」表示「无癌症」,「1」表示「癌症」。

import pandas as pd
from sklearn.datasets import load_breast_cancercolumns = ['mean radius', 'mean texture', 'mean perimeter', 'mean area', 'mean smoothness', 'mean compactness', 'mean concavity', 'mean concave points', 'mean symmetry', 'mean fractal dimension', 'radius error', 'texture error', 'perimeter error', 'area error', 'smoothness error', 'compactness error', 'concavity error', 'concave points error', 'symmetry error', 'fractal dimension error', 'worst radius', 'worst texture', 'worst perimeter', 'worst area', 'worst smoothness', 'worst compactness', 'worst concavity', 'worst concave points', 'worst symmetry', 'worst fractal dimension']dataset = load_breast_cancer()
data = pd.DataFrame(dataset['data'], columns=columns)
data['cancer'] = dataset['target']display(data.head())
display(data.info())
display(data.isna().sum())
display(data.describe())

上图是乳腺癌 DataFrame 的一部分。每行是一个患者的观察结果。最后一列名为「cancer」是我们要预测的目标变量。0 表示「无癌症」,1 表示「癌症」。

训练集/测试集分割

现在,我们使用 Scikit-learn 的「train_test_split」函数拆分数据。我们想让模型有尽可能多的数据进行训练。但是,我们也要确保有足够的数据来测试模型。通常数据集中行数越多,我们可以提供给训练集的数据越多。

例如,如果我们有数百万行,那么我们可以将其中的 90%用作训练,10%用作测试。但是,我们的数据集只有 569 行,数据量并不大。因此,为了匹配这种小型数据集,我们会将数据分为 50%的训练和 50%的测试。我们设置 stratify = y 以确保训练集和测试集与原始数据集的 0 和 1 的比例一致。

from sklearn.model_selection import train_test_splitX = data.drop('cancer', axis=1)  
y = data['cancer'] 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.50, random_state = 2020, stratify=y)

规范化数据

在建模之前,我们需要先将数据「居中」和「标准化」,对不同的变量要在相同尺度进行测量。我们进行缩放以便决定预测变量的特征可以彼此「公平竞争」。我们还将「y_train」从 Pandas「Series」对象转换为 NumPy 数组,以供模型稍后接收训练数据。

import numpy as np
from sklearn.preprocessing import StandardScalerss = StandardScaler()
X_train_scaled = ss.fit_transform(X_train)
X_test_scaled = ss.transform(X_test)
y_train = np.array(y_train)

拟合「基线」随机森林模型

现在,我们创建一个「基线」随机森林模型。该模型使用 Scikit-learn 随机森林分类器文档中定义的所有预测特征和默认设置。首先,我们实例化模型并使用规范化的数据拟合模型。我们可以通过训练数据测量模型的准确性。

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import recall_scorerfc = RandomForestClassifier()
rfc.fit(X_train_scaled, y_train)
display(rfc.score(X_train_scaled, y_train))# 1.0

如果我们想知道哪些特征对随机森林模型预测乳腺癌最重要,我们可以通过调用「feature_importances _」方法来可视化和量化这些重要特征:

feats = {}
for feature, importance in zip(data.columns, rfc_1.feature_importances_):
feats[feature] = importanceimportances = pd.DataFrame.from_dict(feats, orient='index').rename(columns={0: 'Gini-Importance'})
importances = importances.sort_values(by='Gini-Importance', ascending=False)
importances = importances.reset_index()
importances = importances.rename(columns={'index': 'Features'})sns.set(font_scale = 5)
sns.set(style="whitegrid", color_codes=True, font_scale = 1.7)
fig, ax = plt.subplots()
fig.set_size_inches(30,15)
sns.barplot(x=importances['Gini-Importance'], y=importances['Features'], data=importances, color='skyblue')
plt.xlabel('Importance', fontsize=25, weight = 'bold')
plt.ylabel('Features', fontsize=25, weight = 'bold')
plt.title('Feature Importance', fontsize=25, weight = 'bold')display(plt.show())
display(importances)

主成分分析(PCA)

现在,我们如何改进基线模型呢?使用降维,我们可以用更少的变量来拟合原始数据集,同时降低运行模型的计算花销。使用 PCA,我们可以研究这些特征的累积方差比,以了解哪些特征代表数据中的最大方差。

我们实例化 PCA 函数并设置我们要考虑的成分(特征)数量。此处我们设置为 30,以查看所有生成成分的方差,并决定在何处切割。然后,我们将缩放后的 X_train 数据「拟合」到 PCA 函数中。

import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.decomposition import PCApca_test = PCA(n_components=30)
pca_test.fit(X_train_scaled)sns.set(style='whitegrid')
plt.plot(np.cumsum(pca_test.explained_variance_ratio_))
plt.xlabel('number of components')
plt.ylabel('cumulative explained variance')
plt.axvline(linewidth=4, color='r', linestyle = '--', x=10, ymin=0, ymax=1)
display(plt.show())evr = pca_test.explained_variance_ratio_
cvr = np.cumsum(pca_test.explained_variance_ratio_)pca_df = pd.DataFrame()
pca_df['Cumulative Variance Ratio'] = cvr
pca_df['Explained Variance Ratio'] = evr
display(pca_df.head(10))

该图显示,在超过 10 个特征之后,我们并未获得太多的解释方差。此 DataFrame 显示了累积方差比(解释了数据的总方差)和解释方差比(每个 PCA 成分说明了多少数据的总方差)。

从上面的 DataFrame 可以看出,当我们使用 PCA 将 30 个预测变量减少到 10 个分量时,我们仍然可以解释 95%以上的方差。其他 20 个分量仅解释了不到 5%的方差,因此 我们可以减少他们的权重。按此逻辑,我们将使用 PCA 将 X_train 和 X_test 的成分数量从 30 个减少到 10 个。我们将这些重新创建的「降维」数据集分配给「X_train_scaled_pca」和「X_test_scaled_pca」。

pca = PCA(n_components=10)
pca.fit(X_train_scaled)X_train_scaled_pca = pca.transform(X_train_scaled)
X_test_scaled_pca = pca.transform(X_test_scaled)

每个分量都是原始变量和相应「权重」的线性组合。通过创建一个 DataFrame,我们可以看到每个 PCA 成分的「权重」。

pca_dims = []
for x in range(0, len(pca_df)):
pca_dims.append('PCA Component {}'.format(x))pca_test_df = pd.DataFrame(pca_test.components_, columns=columns, index=pca_dims)
pca_test_df.head(10).T

PCA 后拟合「基线」随机森林模型

现在,我们可以将 X_train_scaled_pca 和 y_train 数据拟合到另一个「基线」随机森林模型中,测试我们对该模型的预测是否有所改进。

rfc = RandomForestClassifier()
rfc.fit(X_train_scaled_pca, y_train)display(rfc.score(X_train_scaled_pca, y_train))# 1.0

第 1 轮超参数调优:RandomSearchCV

实现 PCA 之后,我们还可以通过一些超参数调优来调整我们的随机森林以获得更好的预测效果。超参数可以看作模型的「设置」。两个不同数据集的理想设置并不相同,因此我们必须「调整」模型。

首先,我们可以从 RandomSearchCV 开始考虑更多的超参值。所有随机森林的超参数都可以在 Scikit-learn 随机森林分类器文档中找到。

我们生成一个「param_dist」,其值的范围适用于每个超参数。实例化 RandomSearchCV,首先传入我们的随机森林模型,然后传入「param_dist」、测试迭代次数以及交叉验证次数。

超参数「n_jobs」可以决定要使用多少处理器内核来运行模型。设置「n_jobs = -1」将使模型运行最快,因为它使用了所有计算机核心。

我们将调整这些超参数:

  • n_estimators:随机森林中「树」的数量。

  • max_features:每个分割处的特征数。

  • max_depth:每棵树可以拥有的最大「分裂」数。

  • min_samples_split:在树的节点分裂前所需的最少观察数。

  • min_samples_leaf:每棵树末端的叶节点所需的最少观察数。

  • bootstrap:是否使用 bootstrapping 来为随机林中的每棵树提供数据。(bootstrapping 是从数据集中进行替换的随机抽样。)

from sklearn.model_selection import RandomizedSearchCVn_estimators = [int(x) for x in np.linspace(start = 100, stop = 1000, num = 10)]max_features = ['log2', 'sqrt']max_depth = [int(x) for x in np.linspace(start = 1, stop = 15, num = 15)]min_samples_split = [int(x) for x in np.linspace(start = 2, stop = 50, num = 10)]min_samples_leaf = [int(x) for x in np.linspace(start = 2, stop = 50, num = 10)]bootstrap = [True, False]param_dist = {'n_estimators': n_estimators,
'max_features': max_features,
'max_depth': max_depth,
'min_samples_split': min_samples_split,
'min_samples_leaf': min_samples_leaf,
'bootstrap': bootstrap}rs = RandomizedSearchCV(rfc_2, 
param_dist, 
n_iter = 100, 
cv = 3, 
verbose = 1, 
n_jobs=-1, 
random_state=0)rs.fit(X_train_scaled_pca, y_train)
rs.best_params_————————————————————————————————————————————
# {'n_estimators': 700,
# 'min_samples_split': 2,
# 'min_samples_leaf': 2,
# 'max_features': 'log2',
# 'max_depth': 11,
# 'bootstrap': True}

在 n_iter = 100 且 cv = 3 的情况下,我们创建了 300 个随机森林模型,对上面输入的超参数进行随机采样组合。我们可以调用「best_params」以获取性能最佳的模型参数(如上面代码框底部所示)。

但是,现阶段的「best_params」可能无法为我们提供最有效的信息,以获取一系列参数来执行下一次超参数调整。为了在更大范围内进行尝试,我们可以轻松地获得 RandomSearchCV 结果的 DataFrame。

rs_df = pd.DataFrame(rs.cv_results_).sort_values('rank_test_score').reset_index(drop=True)
rs_df = rs_df.drop([
'mean_fit_time', 
'std_fit_time', 
'mean_score_time',
'std_score_time', 
'params', 
'split0_test_score', 
'split1_test_score', 
'split2_test_score', 
'std_test_score'],
axis=1)
rs_df.head(10)


现在,让我们在 x 轴上创建每个超参数的柱状图,并针对每个值制作模型的平均得分,查看平均而言最优的值:

fig, axs = plt.subplots(ncols=3, nrows=2)
sns.set(style="whitegrid", color_codes=True, font_scale = 2)
fig.set_size_inches(30,25)sns.barplot(x='param_n_estimators', y='mean_test_score', data=rs_df, ax=axs[0,0], color='lightgrey')
axs[0,0].set_ylim([.83,.93])axs[0,0].set_title(label = 'n_estimators', size=30, weight='bold')sns.barplot(x='param_min_samples_split', y='mean_test_score', data=rs_df, ax=axs[0,1], color='coral')
axs[0,1].set_ylim([.85,.93])axs[0,1].set_title(label = 'min_samples_split', size=30, weight='bold')sns.barplot(x='param_min_samples_leaf', y='mean_test_score', data=rs_df, ax=axs[0,2], color='lightgreen')
axs[0,2].set_ylim([.80,.93])axs[0,2].set_title(label = 'min_samples_leaf', size=30, weight='bold')sns.barplot(x='param_max_features', y='mean_test_score', data=rs_df, ax=axs[1,0], color='wheat')
axs[1,0].set_ylim([.88,.92])axs[1,0].set_title(label = 'max_features', size=30, weight='bold')sns.barplot(x='param_max_depth', y='mean_test_score', data=rs_df, ax=axs[1,1], color='lightpink')
axs[1,1].set_ylim([.80,.93])axs[1,1].set_title(label = 'max_depth', size=30, weight='bold')sns.barplot(x='param_bootstrap',y='mean_test_score', data=rs_df, ax=axs[1,2], color='skyblue')
axs[1,2].set_ylim([.88,.92])

通过上面的图,我们可以了解每个超参数的值的平均执行情况。

  • n_estimators:300、500、700 的平均分数几乎最高;

  • min_samples_split:较小的值(如 2 和 7)得分较高。23 处得分也很高。我们可以尝试一些大于 2 的值,以及 23 附近的值;

  •  min_samples_leaf:较小的值可能得到更高的分,我们可以尝试使用 2–7 之间的值;

  •  max_features:「sqrt」具有最高平均分;

  •  max_depth:没有明确的结果,但是 2、3、7、11、15 的效果很好;

  • bootstrap:「False」具有最高平均分。

现在我们可以利用这些结论,进入第二轮超参数调整,以进一步缩小选择范围。

第 2 轮超参数调整:GridSearchCV

使用 RandomSearchCV 之后,我们可以使用 GridSearchCV 对目前最佳超参数执行更精细的搜索。超参数是相同的,但是现在我们使用 GridSearchCV 执行更「详尽」的搜索。

在 GridSearchCV 中,我们尝试每个超参数的单独组合,这比 RandomSearchCV 所需的计算力要多得多,在这里我们可以直接控制要尝试的迭代次数。例如,仅对 6 个参数搜索 10 个不同的参数值,具有 3 折交叉验证,则需要拟合模型 3,000,000 次!这就是为什么我们在使用 RandomSearchCV 之后执行 GridSearchCV,这能帮助我们首先缩小搜索范围。

因此,利用我们从 RandomizedSearchCV 中学到的知识,代入每个超参数的平均最佳执行范围:

from sklearn.model_selection import GridSearchCVn_estimators = [300,500,700]
max_features = ['sqrt']
max_depth = [2,3,7,11,15]
min_samples_split = [2,3,4,22,23,24]
min_samples_leaf = [2,3,4,5,6,7]
bootstrap = [False]param_grid = {'n_estimators': n_estimators,
'max_features': max_features,
'max_depth': max_depth,
'min_samples_split': min_samples_split,
'min_samples_leaf': min_samples_leaf,
'bootstrap': bootstrap}gs = GridSearchCV(rfc_2, param_grid, cv = 3, verbose = 1, n_jobs=-1)
gs.fit(X_train_scaled_pca, y_train)
rfc_3 = gs.best_estimator_
gs.best_params_————————————————————————————————————————————
# {'bootstrap': False,
# 'max_depth': 7,
# 'max_features': 'sqrt',
# 'min_samples_leaf': 3,
# 'min_samples_split': 2,
# 'n_estimators': 500}

在这里我们将对 3x 1 x 5x 6 x 6 x 1 = 540 个模型进行 3 折交叉验证,总共是 1,620 个模型!现在,在执行 RandomizedSearchCV 和 GridSearchCV 之后,我们 可以调用「best_params_」获得一个最佳模型来预测我们的数据(如上面代码框的底部所示)。

根据测试数据评估模型的性能

现在,我们可以在测试数据上评估我们建立的模型。我们会测试 3 个模型:

  • 基线随机森林

  • 具有 PCA 降维的基线随机森林

  • 具有 PCA 降维和超参数调优的基线随机森林

让我们为每个模型生成预测结果:

y_pred = rfc.predict(X_test_scaled)
y_pred_pca = rfc.predict(X_test_scaled_pca)
y_pred_gs = gs.best_estimator_.predict(X_test_scaled_pca)

然后,我们为每个模型创建混淆矩阵,查看每个模型对乳腺癌的预测能力:

from sklearn.metrics import confusion_matrixconf_matrix_baseline = pd.DataFrame(confusion_matrix(y_test, y_pred), index = ['actual 0', 'actual 1'], columns = ['predicted 0', 'predicted 1'])conf_matrix_baseline_pca = pd.DataFrame(confusion_matrix(y_test, y_pred_pca), index = ['actual 0', 'actual 1'], columns = ['predicted 0', 'predicted 1'])conf_matrix_tuned_pca = pd.DataFrame(confusion_matrix(y_test, y_pred_gs), index = ['actual 0', 'actual 1'], columns = ['predicted 0', 'predicted 1'])display(conf_matrix_baseline)
display('Baseline Random Forest recall score', recall_score(y_test, y_pred))
display(conf_matrix_baseline_pca)
display('Baseline Random Forest With PCA recall score', recall_score(y_test, y_pred_pca))
display(conf_matrix_tuned_pca)
display('Hyperparameter Tuned Random Forest With PCA Reduced Dimensionality recall score', recall_score(y_test, y_pred_gs))

下面是预测结果:

我们将召回率作为性能指标,因为我们处理的是癌症诊断,我们最关心的是将模型中的假阴性预测误差最小。

考虑到这一点,看起来我们的基线随机森林模型表现最好,召回得分为 94.97%。根据我们的测试数据集,基线模型可以正确预测 179 名癌症患者中的 170 名。

这个案例研究提出了一个重要的注意事项:有时,在 PCA 之后,甚至在进行大量的超参数调整之后,调整的模型性能可能不如普通的「原始」模型。但是尝试很重要,你不尝试,就永远都不知道哪种模型最好。在预测癌症方面,模型越好,可以挽救的生命就更多。

原文链接:

https://towardsdatascience.com/machine-learning-step-by-step-6fbde95c455a

本文转自:机器之心 公众号;

「END」

版权声明:本号内容部分来自互联网,转载请注明原文链接和作者,如有侵权或出处有误请和我们联系。

更多相关知识请回复:“ 月光宝盒 ”;

数据分析(ID : ecshujufenxi )互联网科技与数据圈自己的微信,也是WeMedia自媒体联盟成员之一,WeMedia联盟覆盖5000万人群。

这篇关于机器学习第一步,这是一篇手把手的随机森林入门实战的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/943266

相关文章

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

在Java中使用ModelMapper简化Shapefile属性转JavaBean实战过程

《在Java中使用ModelMapper简化Shapefile属性转JavaBean实战过程》本文介绍了在Java中使用ModelMapper库简化Shapefile属性转JavaBean的过程,对比... 目录前言一、原始的处理办法1、使用Set方法来转换2、使用构造方法转换二、基于ModelMapper

Java实战之自助进行多张图片合成拼接

《Java实战之自助进行多张图片合成拼接》在当今数字化时代,图像处理技术在各个领域都发挥着至关重要的作用,本文为大家详细介绍了如何使用Java实现多张图片合成拼接,需要的可以了解下... 目录前言一、图片合成需求描述二、图片合成设计与实现1、编程语言2、基础数据准备3、图片合成流程4、图片合成实现三、总结前

nginx-rtmp-module构建流媒体直播服务器实战指南

《nginx-rtmp-module构建流媒体直播服务器实战指南》本文主要介绍了nginx-rtmp-module构建流媒体直播服务器实战指南,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. RTMP协议介绍与应用RTMP协议的原理RTMP协议的应用RTMP与现代流媒体技术的关系2

C语言小项目实战之通讯录功能

《C语言小项目实战之通讯录功能》:本文主要介绍如何设计和实现一个简单的通讯录管理系统,包括联系人信息的存储、增加、删除、查找、修改和排序等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录功能介绍:添加联系人模块显示联系人模块删除联系人模块查找联系人模块修改联系人模块排序联系人模块源代码如下

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

Golang使用minio替代文件系统的实战教程

《Golang使用minio替代文件系统的实战教程》本文讨论项目开发中直接文件系统的限制或不足,接着介绍Minio对象存储的优势,同时给出Golang的实际示例代码,包括初始化客户端、读取minio对... 目录文件系统 vs Minio文件系统不足:对象存储:miniogolang连接Minio配置Min

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一