入门指南#

Scikit-learn 是一个开源机器学习库,支持监督学习和无监督学习。它还提供了用于模型拟合、数据预处理、模型选择、模型评估以及许多其他实用功能的工具。

本指南旨在说明 scikit-learn 的一些主要功能。它假设读者具备机器学习实践(模型拟合、预测、交叉验证等)的基本工作知识。请参阅我们的 安装说明 来安装 scikit-learn,或跳转至 后续步骤 部分获取有关使用 scikit-learn 的额外指导。

拟合与预测:估计器基础#

Scikit-learn 提供了数十种内置的机器学习算法和模型,称为 估计器 (estimators)。每个估计器都可以通过其 fit 方法拟合到某些数据上。

这是一个简单的示例,我们将一个 RandomForestClassifier(随机森林分类器)拟合到一些非常基础的数据上

>>> from sklearn.ensemble import RandomForestClassifier
>>> clf = RandomForestClassifier(random_state=0)
>>> X = [[ 1,  2,  3],  # 2 samples, 3 features
...      [11, 12, 13]]
>>> y = [0, 1]  # classes of each sample
>>> clf.fit(X, y)
RandomForestClassifier(random_state=0)

fit 方法通常接受 2 个输入

  • 样本矩阵(或设计矩阵)XX 的大小通常为 (n_samples, n_features),这意味着样本表示为行,特征表示为列。

  • 目标值 y,对于回归任务它是实数,对于分类任务它是整数(或任何其他离散值集)。对于无监督学习任务,无需指定 yy 通常是一个一维数组,其中第 i 个条目对应于 X 的第 i 个样本(行)的目标值。

Xy 通常被期望为 numpy 数组或等效的 类数组 (array-like) 数据类型,尽管某些估计器可以处理其他格式,例如稀疏矩阵。

一旦估计器被拟合,它就可以用于预测新数据的目标值。你不需要重新训练估计器。

>>> clf.predict(X)  # predict classes of the training data
array([0, 1])
>>> clf.predict([[4, 5, 6], [14, 15, 16]])  # predict classes of new data
array([0, 1])

你可以查看 如何选择合适的估计器,了解如何为你的用例选择正确的模型。

转换器和预处理器#

机器学习工作流通常由不同的部分组成。一个典型的流水线包括一个对数据进行转换或填补的预处理步骤,以及一个用于预测目标值的最终预测器。

scikit-learn 中,预处理器和转换器遵循与估计器对象相同的 API(它们实际上都继承自同一个 BaseEstimator 类)。转换器对象没有 predict 方法,而是有一个 transform 方法,该方法输出一个新转换后的样本矩阵 X

>>> from sklearn.preprocessing import StandardScaler
>>> X = [[0, 15],
...      [1, -10]]
>>> # scale data according to computed scaling values
>>> StandardScaler().fit(X).transform(X)
array([[-1.,  1.],
       [ 1., -1.]])

有时,你希望对不同的特征应用不同的转换:ColumnTransformer 就是为这些用例设计的。

流水线:链接预处理器和估计器#

转换器和估计器(预测器)可以组合成一个单一的统一对象:Pipeline。流水线提供了与常规估计器相同的 API:它可以通过 fitpredict 进行拟合和预测。正如我们稍后将看到的,使用流水线还可以防止数据泄漏,即防止在训练数据中泄露测试数据信息。

在下面的示例中,我们 加载 Iris 数据集,将其拆分为训练集和测试集,并计算流水线在测试数据上的准确率分数。

>>> from sklearn.preprocessing import StandardScaler
>>> from sklearn.linear_model import LogisticRegression
>>> from sklearn.pipeline import make_pipeline
>>> from sklearn.datasets import load_iris
>>> from sklearn.model_selection import train_test_split
>>> from sklearn.metrics import accuracy_score
...
>>> # create a pipeline object
>>> pipe = make_pipeline(
...     StandardScaler(),
...     LogisticRegression()
... )
...
>>> # load the iris dataset and split it into train and test sets
>>> X, y = load_iris(return_X_y=True)
>>> X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
...
>>> # fit the whole pipeline
>>> pipe.fit(X_train, y_train)
Pipeline(steps=[('standardscaler', StandardScaler()),
                ('logisticregression', LogisticRegression())])
>>> # we can now use it like any other estimator
>>> accuracy_score(pipe.predict(X_test), y_test)
0.97...

模型评估#

将模型拟合到某些数据上并不意味着它能在未见数据上表现良好。这需要进行直接评估。我们刚刚看到了 train_test_split 辅助工具,它可以将数据集拆分为训练集和测试集,但 scikit-learn 还提供了许多其他模型评估工具,特别是用于 交叉验证 的工具。

我们在此简要展示如何使用 cross_validate 辅助工具执行 5 折交叉验证过程。请注意,也可以手动迭代折叠、使用不同的数据拆分策略以及使用自定义评分函数。详情请参阅我们的 用户指南

>>> from sklearn.datasets import make_regression
>>> from sklearn.linear_model import LinearRegression
>>> from sklearn.model_selection import cross_validate
...
>>> X, y = make_regression(n_samples=1000, random_state=0)
>>> lr = LinearRegression()
...
>>> result = cross_validate(lr, X, y)  # defaults to 5-fold CV
>>> result['test_score']  # r_squared score is high because dataset is easy
array([1., 1., 1., 1., 1.])

自动参数搜索#

所有估计器都有参数(文献中通常称为超参数),这些参数是可以调整的。估计器的泛化能力通常在很大程度上取决于几个参数。例如,RandomForestRegressor 有一个 n_estimators 参数用于决定森林中树的数量,还有一个 max_depth 参数用于决定每棵树的最大深度。通常,这些参数的确切值并不明确,因为它们取决于手头的数据。

Scikit-learn 提供了自动查找最佳参数组合的工具(通过交叉验证)。在以下示例中,我们使用 RandomizedSearchCV 对象在随机森林的参数空间中进行随机搜索。当搜索结束时,RandomizedSearchCV 的行为就像一个已经使用最佳参数集拟合好的 RandomForestRegressor。更多信息请阅读 用户指南

>>> from sklearn.datasets import make_regression
>>> from sklearn.ensemble import RandomForestRegressor
>>> from sklearn.model_selection import RandomizedSearchCV
>>> from sklearn.model_selection import train_test_split
>>> from scipy.stats import randint
...
>>> # create a synthetic dataset
>>> X, y = make_regression(n_samples=20640,
...                        n_features=8,
...                        noise=0.1,
...                        random_state=0)
>>> X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
...
>>> # define the parameter space that will be searched over
>>> param_distributions = {'n_estimators': randint(1, 5),
...                        'max_depth': randint(5, 10)}
...
>>> # now create a searchCV object and fit it to the data
>>> search = RandomizedSearchCV(estimator=RandomForestRegressor(random_state=0),
...                             n_iter=5,
...                             param_distributions=param_distributions,
...                             random_state=0)
>>> search.fit(X_train, y_train)
RandomizedSearchCV(estimator=RandomForestRegressor(random_state=0), n_iter=5,
                   param_distributions={'max_depth': ...,
                                        'n_estimators': ...},
                   random_state=0)
>>> search.best_params_
{'max_depth': 9, 'n_estimators': 4}

>>> # the search object now acts like a normal random forest estimator
>>> # with max_depth=9 and n_estimators=4
>>> search.score(X_test, y_test)
0.84...

注意

在实践中,你几乎总是希望 在流水线上搜索,而不是针对单个估计器。主要原因之一是:如果你在没有使用流水线的情况下对整个数据集应用预处理步骤,然后进行任何类型的交叉验证,你就会破坏训练数据和测试数据之间独立性的基本假设。事实上,由于你是使用整个数据集对数据进行预处理的,关于测试集的一些信息已经泄露给了训练集。这将导致对估计器的泛化能力估计过高(你可以阅读这篇 Kaggle 文章 了解更多信息)。

使用流水线进行交叉验证和搜索将很大程度上使你免受这种常见的陷阱。

后续步骤#

我们简要介绍了估计器拟合与预测、预处理步骤、流水线、交叉验证工具和自动超参数搜索。本指南应能让你概览该库的一些主要功能,但 scikit-learn 的内容远不止于此!

请参阅我们的 用户指南 以获取我们提供的所有工具的详细信息。你还可以在 API 参考 中找到公共 API 的详尽列表。

你还可以查看我们众多的 示例,它们展示了 scikit-learn 在许多不同环境下的使用方法,或者查看 外部资源、视频和讲座 获取学习材料。