You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何出现TypeError: DataUndersampler.transform()缺少必填参数'y'?

基于支持向量的自定义欠采样器报错修复

问题概述

自定义的支持向量欠采样器,通过拟合SVC获取支持向量,基于多数类样本到支持向量的距离进行欠采样,但在结合OneVsOneClassifier与Pipeline运行时触发错误:

TypeError: DataUndersampler.transform() missing 1 required positional argument: 'y'

报错根源

  1. 接口不兼容:Scikit-learn的TransformerMixin要求transform方法仅接收特征矩阵X作为参数,但欠采样器需要同时处理X和y,属于重采样器而非普通转换器
  2. 依赖缺失:代码中使用pd.concat但未导入pandas库
  3. 多分类适配问题:原逻辑仅处理二分类场景,与OneVsOneClassifier生成的多二分类子任务不匹配
  4. 参数错误:示例中make_classification的weights数组长度(4)与n_classes=5不匹配

修复方案

改用imblearn的标准重采样器接口(继承BaseSampler),实现_fit_resample方法(该方法支持同时接收X和y),同时修复依赖、适配多分类子任务并修正参数错误。

修正后完整代码

import pandas as pd
from sklearn.base import BaseEstimator
from sklearn.svm import SVC
import numpy as np
from sklearn.multiclass import OneVsOneClassifier
from imblearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier
from imblearn.base import BaseSampler

class SVGBasedUndersampler(BaseSampler, BaseEstimator):
    def __init__(self, random_state=None):
        self.random_state = random_state
        self.svc = SVC(kernel='linear')
        self.majority_class = None
        self.minority_class = None

    def fit(self, X, y):
        # 拟合SVC获取支持向量
        self.svc.fit(X, y)
        # 记录当前二分类子任务的类别分布(适配OneVsOne逻辑)
        class_counts = pd.Series(y).value_counts()
        self.majority_class = class_counts.idxmax()
        self.minority_class = class_counts.idxmin()
        return self

    def _fit_resample(self, X, y):
        # 统一数据格式为DataFrame/Series
        X_df = pd.DataFrame(X) if not isinstance(X, pd.DataFrame) else X
        y_series = pd.Series(y) if not isinstance(y, pd.Series) else y

        # 获取SVC支持向量
        support_vectors = self.svc.support_vectors_

        # 分离多数类与少数类样本
        X_majority = X_df[y_series == self.majority_class]
        y_majority = y_series[y_series == self.majority_class]
        X_minority = X_df[y_series == self.minority_class]
        y_minority = y_series[y_series == self.minority_class]

        # 计算多数类样本到最近支持向量的距离
        distances = np.min(np.linalg.norm(X_majority.values[:, np.newaxis] - support_vectors, axis=2), axis=1)

        # 按距离排序,保留与少数类数量一致的多数类样本
        sorted_indices = np.argsort(distances)
        indices_to_keep = sorted_indices[:len(y_minority)]

        # 合并采样后的数据集并返回numpy数组(兼容后续模型)
        X_resampled = pd.concat([X_majority.iloc[indices_to_keep], X_minority]).values
        y_resampled = pd.concat([y_majority.iloc[indices_to_keep], y_minority]).values

        return X_resampled, y_resampled

# 验证示例
from sklearn.datasets import make_classification

# 修正参数:weights长度与n_classes一致
X, y = make_classification(n_samples=10_000, n_classes=4, weights=[0.226, 0.037, 0.164, 0.573],
                           n_informative=4, random_state=42)

rf_clf = RandomForestClassifier(random_state=234)
resampler = SVGBasedUndersampler(random_state=234)

# 使用imblearn Pipeline兼容重采样器
pipeline = Pipeline([('sampler', resampler), ('clf', rf_clf)])
classifier = OneVsOneClassifier(estimator=pipeline)

# 训练模型
classifier.fit(X, y)
# 测试预测
print("预测结果示例:", classifier.predict(X[:5]))

核心修改点

  • 切换继承类:使用imblearn.base.BaseSampler替代TransformerMixin,实现_fit_resample方法满足重采样器接口要求
  • 适配多分类:在fit阶段记录当前二分类子任务的类别分布,确保OneVsOneClassifier的每个子任务都能正确执行欠采样
  • 补充依赖:添加pandas导入
  • 参数修正:调整make_classification的参数,确保weights与类别数匹配
  • 格式兼容:将最终返回数据转为numpy数组,适配后续Scikit-learn模型输入要求

内容的提问来源于stack exchange,提问作者arilwan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 04:14:54