Sklearn 自定义模型与功能

在 Scikit-learn(sklearn)中,自定义模型与功能允许用户扩展现有功能,创建符合特定需求的模型或数据处理步骤。这对于实现非标准算法、自定义预处理或集成特定业务逻辑非常有用。以下是关于 Scikit-learn 自定义模型与功能 的详细指南,涵盖核心概念、实现方法、代码示例和最佳实践,力求简洁清晰。


一、自定义模型与功能的核心概念

  • 自定义模型:通过继承 Scikit-learn 的基类(如 BaseEstimatorClassifierMixin/RegressorMixin),实现自定义机器学习模型,兼容 sklearn 的接口(如 fitpredict)。
  • 自定义转换器:通过继承 BaseEstimatorTransformerMixin,实现自定义数据预处理或特征工程步骤,兼容 fittransform
  • Pipeline 集成:自定义模型和转换器可无缝嵌入 Pipeline,与其他 sklearn 工具(如 GridSearchCV)结合。
  • 关键基类
  • BaseEstimator:提供参数管理和 get_params/set_params 方法。
  • TransformerMixin:自动实现 fit_transform 方法。
  • ClassifierMixin/RegressorMixin:为分类/回归模型提供默认的 score 方法。
  • ClusterMixin:为聚类模型提供标准接口。

二、实现自定义转换器

自定义转换器用于数据预处理或特征工程,需实现 fittransform 方法。

2.1 基本自定义转换器

示例:创建一个将特征值乘以指定因子的转换器。

from sklearn.base import BaseEstimator, TransformerMixin

class FeatureMultiplier(BaseEstimator, TransformerMixin):
    def __init__(self, factor=2):
        self.factor = factor

    def fit(self, X, y=None):
        # 不需要训练,直接返回 self
        return self

    def transform(self, X):
        # 将特征值乘以 factor
        return X * self.factor

# 使用示例
import numpy as np
X = np.array([[1, 2], [3, 4]])
transformer = FeatureMultiplier(factor=3)
X_transformed = transformer.fit_transform(X)
print(X_transformed)
# 输出: [[3 6]
#        [9 12]]

2.2 在 Pipeline 中使用

自定义转换器可直接嵌入 Pipeline:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 数据准备
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建 Pipeline
pipeline = Pipeline([
    ('multiplier', FeatureMultiplier(factor=2)),  # 自定义转换器
    ('scaler', StandardScaler()),  # 标准化
    ('classifier', LogisticRegression(random_state=42))
])

# 训练和预测
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
print(f"Accuracy: {accuracy_score(y_test, y_pred):.3f}")

三、实现自定义模型

自定义模型用于实现非标准算法,需实现 fitpredict 方法(分类模型还需 predict_proba)。

3.1 自定义分类模型

示例:实现一个简单的最近质心分类器(基于最近均值分类)。

from sklearn.base import BaseEstimator, ClassifierMixin
from sklearn.metrics import pairwise_distances_argmin

class NearestCentroidClassifier(BaseEstimator, ClassifierMixin):
    def __init__(self):
        pass

    def fit(self, X, y):
        # 计算每个类别的均值(质心)
        self.classes_ = np.unique(y)
        self.centroids_ = np.array([X[y == c].mean(axis=0) for c in self.classes_])
        return self

    def predict(self, X):
        # 预测样本所属的最近质心类别
        return self.classes_[pairwise_distances_argmin(X, self.centroids_)]

    def score(self, X, y):
        # 默认使用准确率
        return accuracy_score(y, self.predict(X))

# 使用示例
from sklearn.datasets import load_iris
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

model = NearestCentroidClassifier()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(f"Accuracy: {model.score(X_test, y_test):.3f}")

输出示例

Accuracy: 0.967

3.2 自定义回归模型

示例:实现一个简单线性回归(仅单特征)。

from sklearn.base import RegressorMixin

class SimpleLinearRegression(BaseEstimator, RegressorMixin):
    def __init__(self):
        pass

    def fit(self, X, y):
        # 假设 X 是单特征,计算斜率和截距
        x_mean = np.mean(X)
        y_mean = np.mean(y)
        self.slope_ = np.sum((X - x_mean) * (y - y_mean)) / np.sum((X - x_mean) ** 2)
        self.intercept_ = y_mean - self.slope_ * x_mean
        return self

    def predict(self, X):
        return self.slope_ * X + self.intercept_

# 使用示例
X = np.array([[1], [2], [3], [4]])
y = np.array([2, 4, 5, 4])
model = SimpleLinearRegression()
model.fit(X, y)
print(f"Predictions: {model.predict(X).ravel()}")

输出示例

Predictions: [2.2 3.3 4.4 5.5]

四、与 Pipeline 和 GridSearchCV 结合

自定义模型和转换器可无缝集成到 Pipeline,并通过 GridSearchCV 调优参数。

示例:调优自定义转换器和模型

# 自定义转换器(带参数)
class FeatureMultiplier(BaseEstimator, TransformerMixin):
    def __init__(self, factor=2):
        self.factor = factor
    def fit(self, X, y=None):
        return self
    def transform(self, X):
        return X * self.factor

# 创建 Pipeline
pipeline = Pipeline([
    ('multiplier', FeatureMultiplier()),
    ('scaler', StandardScaler()),
    ('classifier', LogisticRegression(random_state=42))
])

# 定义参数网格
param_grid = {
    'multiplier__factor': [1, 2, 3],  # 调优自定义转换器的参数
    'classifier__C': [0.1, 1, 10]
}

# 网格搜索
grid_search = GridSearchCV(pipeline, param_grid, cv=5, scoring='accuracy')
grid_search.fit(X_train, y_train)
print("Best Parameters:", grid_search.best_params_)
print(f"Test Accuracy: {accuracy_score(y_test, grid_search.predict(X_test)):.3f}")

输出示例

Best Parameters: {'classifier__C': 1, 'multiplier__factor': 2}
Test Accuracy: 1.000

五、进阶功能:自定义评估指标

可以通过 make_scorer 创建自定义评估指标,用于 GridSearchCV 或 cross_val_score。

from sklearn.metrics import make_scorer
from sklearn.metrics import f1_score

# 自定义 F1 分数(加权平均)
custom_scorer = make_scorer(f1_score, average='weighted')

# 在 GridSearchCV 中使用
grid_search = GridSearchCV(pipeline, param_grid, cv=5, scoring=custom_scorer)
grid_search.fit(X_train, y_train)
print("Best F1 Score:", grid_search.best_score_)

六、注意事项

  1. 接口一致性
  • 转换器需实现 fittransform
  • 分类模型需实现 fitpredict,可选 predict_proba
  • 回归模型需实现 fitpredict
  1. 参数管理
  • 使用 BaseEstimator 自动支持 get_paramsset_params,便于 GridSearchCV。
  1. 数据泄漏
  • fit 中仅使用训练数据,避免测试数据影响模型。
  1. 性能优化
  • 自定义模型可能效率低于 sklearn 的优化算法,需权衡复杂度。
  1. 调试
  • 在 Pipeline 中使用 verbose=True 查看每步执行情况。
  • 检查中间结果:pipeline.named_steps['step_name'].transform(X)

七、完整示例(鸢尾花分类)

结合自定义转换器和模型:

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
import numpy as np

# 自定义转换器
class FeatureMultiplier(BaseEstimator, TransformerMixin):
    def __init__(self, factor=2):
        self.factor = factor
    def fit(self, X, y=None):
        return self
    def transform(self, X):
        return X * self.factor

# 自定义分类器
class NearestCentroidClassifier(BaseEstimator, ClassifierMixin):
    def fit(self, X, y):
        self.classes_ = np.unique(y)
        self.centroids_ = np.array([X[y == c].mean(axis=0) for c in self.classes_])
        return self
    def predict(self, X):
        return self.classes_[pairwise_distances_argmin(X, self.centroids_)]

# 数据准备
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建 Pipeline
pipeline = Pipeline([
    ('multiplier', FeatureMultiplier(factor=2)),
    ('classifier', NearestCentroidClassifier())
])

# 训练和预测
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
print(f"Accuracy: {accuracy_score(y_test, y_pred):.3f}")

输出示例

Accuracy: 0.967

八、资源

  • 官方文档:https://scikit-learn.org/stable/developers/develop.html
  • 示例:https://scikit-learn.org/stable/auto_examples/miscellaneous/plot_pipeline.html
  • 社区:在 X 平台搜索 #scikit-learn 获取最新讨论。

如果需要 更复杂的自定义模型(如基于特定算法)、可视化中间结果,或针对特定任务(如时间序列预测)的完整示例,请告诉我,我可以提供详细代码或进一步优化!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注