Scikit-learn是一个开源的机器学习库,它支持监督学习和无监督学习。该库提供了多种工具,包括模型拟合、数据预处理、模型选择、模型评估等。本指南假设已经具备了机器学习的基础知识,如模型拟合、预测、交叉验证等,并提供了安装Scikit-learn的指导。
Scikit-learn提供了许多内置的机器学习算法和模型,这些被称为估计器(estimators)。每个估计器都可以使用其fit方法拟合到一些数据上。例如,可以将RandomForestClassifier拟合到一些基础数据上,如下所示:
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(random_state=0)
X = [[1, 2, 3], [11, 12, 13]] # 2个样本,每个样本3个特征
y = [0, 1] # 每个样本的类别
clf.fit(X, y)
fit方法通常接受两个输入:样本矩阵(或设计矩阵)X和目标值y。X的大小通常是(n_samples, n_features),意味着样本以行表示,特征以列表示。对于回归任务,y是实数;对于分类任务,y是整数(或其他离散值集)。在无监督学习任务中,不需要指定y。通常,X和y都应该是numpy数组或等效的数组类型数据,尽管一些估计器也可以处理其他格式,如稀疏矩阵。一旦估计器拟合完成,就可以用于预测新数据的目标值,无需重新训练估计器。
机器学习工作流程通常由不同部分组成。一个典型的流程包括一个预处理步骤,该步骤转换或填充数据,以及一个最终的预测器,用于预测目标值。在Scikit-learn中,预处理器和转换器遵循与估计器对象相同的API(它们实际上都继承自同一个BaseEstimator类)。转换器对象没有predict方法,而是有一个transform方法,该方法输出一个新的转换后的样本矩阵X。
from sklearn.preprocessing import StandardScaler
X = [[0, 15], [1, -10]]
scaler = StandardScaler()
X_scaled = scaler.fit(X).transform(X)
有时,可能希望对不同的特征应用不同的转换:ColumnTransformer就是为这些用例设计的。
转换器和估计器(预测器)可以组合在一起,形成一个统一的对象:管道。管道提供与常规估计器相同的API:它可以被拟合并用于预测,使用fit和predict方法。如后文所述,使用管道还可以防止数据泄露,即在训练数据中披露一些测试数据。
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
# 创建管道对象
pipe = make_pipeline(StandardScaler(), LogisticRegression())
# 加载鸢尾花数据集并将其分割为训练集和测试集
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# 拟合整个管道
pipe.fit(X_train, y_train)
# 现在可以使用它像任何其他估计器一样
accuracy = accuracy_score(pipe.predict(X_test), y_test)
模型评估部分介绍了如何评估模型在未见数据上的预测能力。刚刚看到了train_test_split助手,它将数据集分割为训练集和测试集,但Scikit-learn提供了许多其他模型评估工具,特别是交叉验证。
所有估计器都有参数(在文献中通常称为超参数),这些参数可以调整。估计器的泛化能力往往严重依赖于一些参数。例如,RandomForestRegressor有一个n_estimators参数,它决定了森林中的树的数量,还有一个max_depth参数,它决定了每棵树的最大深度。通常,这些参数的确切值并不清楚,因为它们取决于手头的数据。Scikit-learn提供了工具,可以通过交叉验证自动找到最佳参数组合。
from sklearn.datasets import fetch_california_housing
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import RandomizedSearchCV
from sklearn.model_selection import train_test_split
from scipy.stats import randint
X, y = fetch_california_housing(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# 定义将被搜索的参数空间
param_distributions = {
'n_estimators': randint(1, 5),
'max_depth': randint(5, 10)
}
# 现在创建一个searchCV对象并拟合数据
search = RandomizedSearchCV(estimator=RandomForestRegressor(random_state=0), n_iter=5, param_distributions=param_distributions, random_state=0)
search.fit(X_train, y_train)
# search对象现在表现得像一个已经使用最佳参数拟合的普通随机森林估计器
score = search.score(X_test, y_test)
在实践中,几乎总是希望在管道上进行搜索,而不是单个估计器。一个主要原因是,如果在不使用管道的情况下对整个数据集应用预处理步骤,然后进行任何形式的交叉验证,将打破训练和测试数据之间独立性的基本假设。实际上,由于使用整个数据集预处理了数据,测试集中的一些信息对训练集是可用的。这将导致高估估计器的泛化能力(可以在这篇Kaggle帖子中了解更多)。使用管道进行交叉验证和搜索将大大避免这种常见陷阱。