机器学习新手求助:不平衡医疗文本二分类模型输出单一问题
嘿,作为机器学习新手碰到这种类别不平衡导致模型输出几乎一致的问题太常见了,结合你的描述和给出的模型代码,我给你梳理几个针对性的解决方向:
一、先修正类别权重的设置
你当前的class_weight={1: 1, 0: 0.2}明显搞反了逻辑!如果类别0是占比更高的多数类,给它更低的权重会让模型更不在乎它,反而会往少数类偏,但实际你遇到的是输出完全相同,大概率是类别1是少数类,你给它的权重没到位。
正确的类别权重计算应该是:权重 = 总样本数 / (类别数量 * 该类样本数)。比如假设训练集572条里,类别0有500条,类别1只有72条,那类别1的权重就是572/(2*72)≈4,所以应该设成class_weight={0:1, 1:4},这样模型才会重视少数类的样本。
二、优化模型结构,适配文本数据
你现在用的是纯全连接网络,对于Tokenizer处理后的医疗文本,这种结构很难捕捉到文本的语义信息,试试这些调整:
- 加入Embedding层(如果用的是序列数据):如果你是把文本转成了序列(不是one-hot词袋),一定要加Embedding层来把离散的词ID转成连续的语义向量:
sequential_model = keras.Sequential([ # max_seq_length是你的文本统一后的最大长度 layers.Embedding(vocab_size, 64, input_length=max_seq_length), # 用GlobalAveragePooling1D压缩序列,或者用LSTM/GRU捕捉上下文 layers.GlobalAveragePooling1D(), layers.Dense(15, activation='tanh'), layers.BatchNormalization(), layers.Dense(8, activation='relu'), layers.BatchNormalization(), layers.Dense(1, activation='sigmoid') ]) - 加正则化防止过拟合:类别不平衡场景下模型很容易过拟合到多数类,加入Dropout层打乱权重:
sequential_model = keras.Sequential([ layers.Dense(15, activation='tanh',input_dim=vocab_size), layers.BatchNormalization(), layers.Dropout(0.3), # 随机丢弃30%的神经元 layers.Dense(8, activation='relu'), layers.BatchNormalization(), layers.Dropout(0.2), layers.Dense(1, activation='sigmoid') ]) - 调低学习率:Adam默认的学习率(0.001)可能太高,试试
optimizer=keras.optimizers.Adam(learning_rate=1e-4),让模型更平稳地学习少数类的特征。
三、从数据层面解决不平衡问题
模型调参见效慢的话,先从数据入手,这是解决类别不平衡的核心:
- 过采样少数类:用SMOTE算法给少数类生成新的样本(适合数值型特征,比如词袋模型),用
imblearn库就能实现:from imblearn.over_sampling import SMOTE sm = SMOTE(random_state=42) train_data_resampled, train_labels_resampled = sm.fit_resample(train_data, train_labels) - 文本数据增强:针对医疗文本,你可以做同义词替换、随机插入专业词汇、回译(把文本翻译成英文再译回来)等操作,生成更多少数类样本,比如用
nlpaug库来快速实现。 - 欠采样多数类:如果多数类样本太多,随机删掉一部分,让两类比例接近,但注意别删太多导致信息丢失。
四、换用更合理的评估指标
你现在用的acc(准确率)在类别不平衡场景下完全没用!比如90%样本是类别0,模型全预测0也能拿90%准确率,但这根本不是你要的效果。换成这些指标:
sequential_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['precision', 'recall', 'AUC'])
精确率、召回率能直接反映模型对少数类的预测能力,AUC-ROC则能衡量整体的分类效果。
五、关于to_categorical的小说明
你用了to_categorical但没效果,是因为你的模型是单输出的sigmoid设置,to_categorical是给多分类(输出层用softmax)用的。二分类用sigmoid+binary_crossentropy完全没问题,不用强行改这个。
建议你先从修正类别权重和更换评估指标开始,这两个最容易快速看到变化,然后再逐步尝试模型结构调整和数据处理的方法,一步步排查问题。
内容的提问来源于stack exchange,提问作者Yaroslav Shulyak

