在最新的scikit-learn版本中,引入了许多错误修复和性能改进,以及一些关键的新特性。以下是这个版本的主要亮点。如需查看所有更改的详尽列表,请参考发布说明。
要安装最新版本,可以使用pip:
pip install --upgradescikit-learn
或者使用conda:
conda install -c conda-forgescikit-learn
在机器学习任务中,经常需要根据特定问题调整分类器的决策阈值。在scikit-learn中,所有二元分类器默认使用0.5作为决策阈值,将概率估计(即predict_proba的输出)转换为类别预测。然而,对于给定问题,0.5几乎从来都不是理想的阈值。
为了解决这个问题,引入了FixedThresholdClassifier,它允许包装任何二元分类器并设置自定义决策阈值。以下是如何使用FixedThresholdClassifier的示例代码:
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import ConfusionMatrixDisplay
X, y = make_classification(n_samples=10000, weights=[0.9, 0.1], random_state=0)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
classifier_05 = LogisticRegression(C=1e6, random_state=0).fit(X_train, y_train)
_ = ConfusionMatrixDisplay.from_estimator(classifier_05, X_test, y_test)
通过降低阈值,即允许更多样本被分类为正类,可以增加真正例的数量,但代价是增加了假正例的数量(这在ROC曲线的凹形中是众所周知的)。
还引入了TunedThresholdClassifierCV,它允许使用给定的度量标准来调整二元分类器的决策阈值。这在模型部署到特定应用上下文时特别有用,可以为真正例、真负例、假正例和假负例分配不同的收益或成本。
例如,可以定义一个自定义评分函数来量化每个样本的平均利润,如下所示:
from sklearn.metrics import confusion_matrix
def custom_score(y_observed, y_pred):
tn, fp, fn, tp = confusion_matrix(y_observed, y_pred, normalize="all").ravel()
return tp - 2 * fn - 0.1 * fp
print("未调整的决策阈值: 0.5")
print(f"自定义评分: {custom_score(y_test, classifier_05.predict(X_test)):.2f}")
通过调整决策阈值来优化这个自定义度量,可以得到一个更小的阈值,允许更多样本被分类为正类。结果,每个预测的平均收益得到了改善。
在实际应用中,定义一个有意义的特定于应用的度量可能涉及根据每个个体数据点的辅助元数据(如欺诈检测系统中的交易金额)来确定坏预测的成本和好预测的收益。
为了实现这一点,TunedThresholdClassifierCV利用了元数据路由支持(Metadata Routing User Guide),允许优化复杂的业务度量,如在“成本敏感学习后调整决策阈值”中详细说明的。
此外,PCA现在有了新的求解器"covariance_eigh",它比其他求解器在数据点多、特征少的数据集上快一个数量级,并且更加内存高效。
from sklearn.datasets import make_low_rank_matrix
from sklearn.decomposition import PCA
X = make_low_rank_matrix(n_samples=10000, n_features=100, tail_strength=0.1, random_state=0)
pca = PCA(n_components=10, svd_solver="covariance_eigh").fit(X)
print(f"解释方差: {pca.explained_variance_ratio_.sum():.2f}")
新的求解器还接受稀疏输入数据:
from scipy.sparse import random
X = random(10000, 100, format="csr", random_state=0)
pca = PCA(n_components=10, svd_solver="covariance_eigh").fit(X)
print(f"解释方差: {pca.explained_variance_ratio_.sum():.2f}")
"full"求解器也得到了改进,使用更少的内存,并允许更快的转换。默认的svd_solver="auto"选项利用了新的求解器,并且现在能够为稀疏数据集选择适当的求解器。
类似于大多数其他PCA求解器,新的"covariance_eigh"求解器也可以利用GPU计算,如果输入数据作为PyTorch或CuPy数组传递,可以通过启用实验性的Array API支持来实现。
ColumnTransformer现在可以通过名称使用索引直接访问其转换器。
import numpy as np
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
X = np.array([[0, 1, 2], [3, 4, 5]])
column_transformer = ColumnTransformer([("std_scaler", StandardScaler(), [0]), ("one_hot", OneHotEncoder(), [1, 2])])
column_transformer.fit(X)
print(column_transformer["std_scaler"])
print(column_transformer["one_hot"])
SimpleImputer现在支持自定义填充策略,使用一个可调用的函数,该函数从列向量的非缺失值中计算一个标量值。
from sklearn.impute import SimpleImputer
X = np.array([[-1.1, 1.1, 1.1], [3.9, -1.2, np.nan], [np.nan, 1.3, np.nan], [-0.1, -1.4, -1.4], [-4.9, 1.5, -1.5], [np.nan, 1.6, 1.6]])
def smallest_abs(arr):
""“返回1D数组的最小绝对值。"""
return np.min(np.abs(arr))
imputer = SimpleImputer(strategy=smallest_abs)
imputer.fit_transform(X)
from sklearn.metrics import pairwise_distances
X = ["cat", "dog"]
Y = ["cat", "fox"]
def levenshtein_distance(x, y):
""“返回两个字符串之间的Levenshtein距离。"""
if x == "" or y == "":
return max(len(x), len(y))
if x[0] == y[0]:
return levenshtein_distance(x[1:], y[1:])
return 1 + min(levenshtein_distance(x[1:], y), levenshtein_distance(x, y[1:]), levenshtein_distance(x[1:], y[1:]))
pairwise_distances(X, Y, metric=levenshtein_distance)