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

使用scikit-learn合并不同维度特征时维度不匹配问题求助

解决scikit-learn Pipeline + FeatureUnion中的维度不匹配问题

你遇到的这个ValueError核心问题是两个特征分支返回的矩阵行数不一致:book_summary返回了2000行(对应你的训练集样本数),但book_contents只返回了1行,导致FeatureUnion无法合并特征。我帮你梳理下问题根源和修复方案:

问题根源拆解

  1. 自定义Transformer不符合scikit-learn规范:你的book_content_count类没有继承BaseEstimator和TransformerMixin,这会让scikit-learn无法正确识别它的接口,容易引发维度处理的隐藏错误。
  2. 变量名错误导致文本读取异常:count_contents2里你定义了book_data = pd.read_csv(...),但后面却用了user_data['text']——这个未定义的变量会导致读取书籍文本失败,返回的内容格式错误,最终让TF-IDF输出异常维度的矩阵。
  3. TF-IDF拟合时机错误:你在transform方法里每次都重新创建并拟合TF-IDF Pipeline,这不仅效率低,还会导致数据泄露(测试时用测试数据拟合),甚至可能因为单样本处理异常返回行数不对的结果。
  4. ItemSelector列名错误:你的数据示例里摘要列是Summary,但book_summary Pipeline里用了key='book',这会导致该分支无法正确提取特征,进一步加剧维度问题。

修复后的完整代码

1. 修正自定义书籍内容Transformer

from sklearn.base import BaseEstimator, TransformerMixin
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.svm import SVC

class BookContentTransformer(BaseEstimator, TransformerMixin):
    def __init__(self):
        # 初始化TF-IDF向量器,参数可以根据需求调整
        self.tfidf = TfidfVectorizer(min_df=1, lowercase=False, ngram_range=(1,1), 
                                     use_idf=True, stop_words='english')
    
    def _load_single_book(self, bookid):
        """加载单个书籍的文本内容并拼接成字符串"""
        try:
            book_path = f'C:/TheCorpus/{int(bookid)}_book.csv'
            book_df = pd.read_csv(book_path, header=0, delimiter=',', 
                                 encoding='latin1', error_bad_lines=False, dtype=str)
            # 把所有文本行拼接成一个完整的书籍文本
            full_text = ' '.join(book_df['text'].astype(str))
            return full_text
        except Exception as e:
            # 处理文件不存在或读取错误的情况,返回空字符串避免中断
            print(f"加载书籍{bookid}失败: {e}")
            return ""
    
    def fit(self, X, y=None):
        """在fit阶段拟合TF-IDF,使用训练集的书籍文本构建词汇表"""
        # 从输入数据中提取所有bookid,加载对应书籍文本
        all_book_texts = X['bookid'].apply(self._load_single_book)
        self.tfidf.fit(all_book_texts)
        return self
    
    def transform(self, X, y=None):
        """将输入的bookid转换为TF-IDF特征矩阵"""
        book_texts = X['bookid'].apply(self._load_single_book)
        # 返回与输入样本数一致的(n_samples, n_features)稀疏矩阵
        return self.tfidf.transform(book_texts)

2. 修正Pipeline和FeatureUnion定义

# 先定义通用的列选择Transformer
class ItemSelector(BaseEstimator, TransformerMixin):
    def __init__(self, key):
        self.key = key
    
    def fit(self, X, y=None):
        return self
    
    def transform(self, X):
        return X[self.key]

# 书籍摘要特征流水线
book_summary_pipeline = Pipeline([
    ('selector', ItemSelector(key='Summary')),  # 修正列名为你的数据集实际列名
    ('tfidf', TfidfVectorizer(analyzer='word', ngram_range=(1,3), min_df=1, 
                              lowercase=True, stop_words=my_stopword_list, sublinear_tf=True))
])

# 书籍内容特征流水线
book_content_pipeline = Pipeline([
    ('selector', ItemSelector(key='bookid')),  # 选择bookid列
    ('content_tfidf', BookContentTransformer())  # 使用修正后的Transformer
])

# 最终完整流水线
full_pipeline = Pipeline([
    ('feats', FeatureUnion([
        ('summary_feats', book_summary_pipeline),
        ('content_feats', book_content_pipeline)
    ])),
    ('clf', SVC(kernel='linear', class_weight='balanced'))
])

关键修复点说明

  • 遵循scikit-learn接口规范:让自定义Transformer继承BaseEstimator和TransformerMixin,确保scikit-learn能正确处理它的fit/transform流程。
  • 修正文本读取逻辑:修复变量名错误,正确拼接单本书籍的所有文本内容,保证每个样本对应一个完整的书籍文本字符串。
  • 正确的TF-IDF拟合时机:把TF-IDF的拟合放在fit方法中,只在训练阶段构建词汇表,测试阶段直接复用,避免数据泄露同时保证维度一致。
  • 匹配列名:确保ItemSelector使用的key和你数据集的列名完全一致,保证每个分支都能提取到正确的样本特征。

这样修改后,两个特征分支都会返回行数等于训练集样本数的特征矩阵,FeatureUnion就能正常合并,后续的SVC分类器也能正常运行了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:17:28