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

使用ktrain与BERT进行文本分类时,SMOTE处理不平衡数据集触发维度错误的问题

问题分析与解决方法

错误原因

你遇到的ValueError: Found array with dim 3. Estimator expected <= 2.本质原因是SMOTE算法的设计限制:

  • SMOTE是为传统机器学习的2维特征矩阵(形状为[样本数量, 特征数量])设计的,它只能处理扁平化的数值特征。
  • 而ktrain的texts_from_df方法在使用BERT预训练模式时,返回的x_train是3维张量(形状通常为[样本数量, 最大序列长度, 特征维度],或者是包含input_ids、attention_mask等多个2D张量的组合),完全不满足SMOTE的输入要求。

简单来说:SMOTE看不懂BERT的序列输入,它只认识扁平的特征向量。


解决方法

根据你的项目场景,推荐三种可行的解决方案,按实现复杂度从低到高排序:

方案1:在BERT预处理前对原始数据做过采样

跳过直接对BERT输入做SMOTE,转而在原始文本数据层面做过采样,再喂给ktrain处理。这里推荐用RandomOverSampler(比SMOTE更适合文本场景,因为SMOTE无法直接生成有意义的文本):

# 先对原始训练数据集做过采样
from imblearn.over_sampling import RandomOverSampler

# 初始化过采样器
ros = RandomOverSampler(random_state=42)
# 对训练集的文本列和标签列进行过采样
train_text_resampled, train_label_resampled = ros.fit_resample(
    data_train[["Tweet"]], 
    data_train["Sentiment"]
)
# 合并回完整的DataFrame
data_train_resampled = pd.concat([train_text_resampled, train_label_resampled], axis=1)

# 用重采样后的数据集生成BERT输入
(x_train,y_train),(x_test,y_test),preprocess =text.texts_from_df(
    train_df=data_train_resampled, 
    text_column="Tweet", 
    label_columns = "Sentiment", 
    val_df = data_test, 
    maxlen = 400, 
    preprocess_mode = 'bert'
)

这种方法的优点是简单直接,不需要修改模型逻辑,适合快速验证效果。

方案2:给BERT模型设置类别权重(推荐)

不需要做任何数据采样,直接在模型训练时通过损失函数的权重来平衡类别。ktrain支持在创建分类器时指定class_weight参数:

# 生成BERT输入(不需要提前采样)
(x_train,y_train),(x_test,y_test),preprocess =text.texts_from_df(
    train_df=data_train, 
    text_column="Tweet", 
    label_columns = "Sentiment", 
    val_df = data_test, 
    maxlen = 400, 
    preprocess_mode = 'bert'
)

# 创建分类器时指定class_weight='balanced',自动给少数类分配更高权重
model = text.text_classifier(
    'bert', 
    (x_train, y_train), 
    preproc=preprocess, 
    class_weight='balanced'
)
learner = ktrain.get_learner(
    model, 
    train_data=(x_train, y_train), 
    val_data=(x_test, y_test), 
    batch_size=8
)

# 后续正常训练即可
learner.fit_onecycle(2e-5, 3)

这种方法是处理类别不平衡的更优方案,因为它不会引入数据冗余或合成无意义的样本,而是让模型主动关注少数类。

方案3:使用文本专用的数据增强方法

如果想生成全新的少数类文本样本(而非重复现有样本),可以用文本数据增强技术,比如EDA(Easy Data Augmentation),或者用预训练语言模型生成新文本:

  • EDA操作包括:同义词替换、随机插入同义词、随机交换词语、随机删除词语
  • 你可以手动实现这些逻辑,或者用现成的库(比如nlpaug)

示例(用nlpaug做同义词替换):

import nlpaug.augmenter.word as naw

# 初始化增强器,用WordNet做同义词替换
aug = naw.SynonymAug(aug_src='wordnet')

# 对少数类样本进行增强
minority_class = data_train[data_train["Sentiment"] == "你的少数类标签"]
augmented_texts = aug.augment(minority_class["Tweet"].tolist(), n=3)  # 每个样本生成3个增强版本

# 把增强后的样本合并到训练集
augmented_df = pd.DataFrame({
    "Tweet": augmented_texts,
    "Sentiment": ["你的少数类标签"] * len(augmented_texts)
})
data_train_resampled = pd.concat([data_train, augmented_df], axis=0)

# 再用这个数据集生成BERT输入

这种方法能丰富训练数据,但需要注意增强后的文本要保持语义一致性,避免引入噪声。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:27:40