多分类文本分类预处理后验证精度下降,求原因分析
我正在开展一个多分类文本分类项目,将数据集划分为训练集和测试集后,对训练集执行了如下预处理函数:
STOPWORDS = set(stopwords.words('english')) def clean_text(text): # 转小写 text = text.lower() # 删除特殊符号 text = re.sub(r"(@\[A-Za-z0-9]+)|([^0-9A-Za-z \t])|(\w+:\/\/\S+)|^rt|http.+?", "", text) # 删除停用词 text = ' '.join(word for word in text.split() if word not in STOPWORDS) # 词干提取 text = ' '.join([stemmer.stem(word) for word in text.split()]) return text
令我意外的是,执行预处理后验证精度(59%)远低于不做任何处理的情况(69%)。我仅注释掉以下代码中的预处理调用行,精度就回升了:
all_data = dataset.sample(frac=1).reset_index(drop=True) train_df, valid = train_test_split(all_data, test_size=0.2) train_df['text'] = train_df['text'].apply(clean_text)
我忽略了什么?为何预处理步骤会导致精度下降?
补充信息:
文本分词代码如下:
X_train = train.iloc[:, :-1] y_train = train.iloc[:, -1:] X_test = valid.iloc[:, :-1] y_test = valid.iloc[:, -1:] weights = class_weight.compute_class_weight(class_weight='balanced', classes=np.unique(y_train), y=y_train.values.reshape(-1)) le = LabelEncoder() le.fit(weights) class_weights_dict = dict(zip(le.transform(list(le.classes_)), weights)) tokenizer = Tokenizer(num_words=vocab_size, oov_token='<OOV>') tokenizer.fit_on_texts(X_train['text']) train_seq = tokenizer.texts_to_sequences(X_train['text']) train_padded = pad_sequences(train_seq, maxlen=max_length, padding=padding_type, truncating=trunc_type) validation_seq = tokenizer.texts_to_sequences(X_test['text']) validation_padded = pad_sequences(validation_seq, maxlen=max_length, padding=padding_type, truncating=trunc_type)
模型结构如下:
model = Sequential() model.add(Embedding(vocab_size, embedding_dim, input_length=train_padded.shape[1])) model.add(Conv1D(48, len(GROUPS), activation='relu', padding='valid')) model.add(GlobalMaxPooling1D()) model.add(Dropout(0.5)) model.add(Flatten()) model.add(Dropout(0.5)) model.add(Dense(len(GROUPS), activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) epochs = 100 batch_size = 32 history = model.fit(train_padded, training_labels, shuffle=True , epochs=epochs, batch_size=batch_size, class_weight=class_weights_dict, validation_data=(validation_padded, validation_labels), callbacks=[ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, min_lr=0.0001), EarlyStopping(monitor='val_loss', mode='min', patience=2, verbose=1), EarlyStopping(monitor='val_accuracy', mode='max', patience=5, verbose=1)])
预处理后精度下降,大概率是以下几个原因导致的,逐个排查即可:
验证集未同步执行预处理
这是最容易犯的错误:你只对训练集做了clean_text处理,但验证集完全是原始状态。模型训练时学习的是预处理后的文本特征,验证时却输入原始文本,两者数据分布完全不匹配,精度必然暴跌。
解决:给验证集也执行完全相同的clean_text预处理,确保训练和验证数据的特征分布一致。停用词删除过度,丢失关键语义特征
默认的英文停用词表包含很多功能性词汇(比如"not"这类否定词),但在分类任务中,这些词往往是区分类别的核心依据——删掉"not"会直接反转文本语义,让模型完全误解输入。
解决:- 检查停用词表,手动移除对当前任务重要的词汇(比如否定词、特定领域的功能性词);
- 单独测试"删除停用词"这一步的影响,确认是不是这步导致的精度下降。
词干提取破坏了有效特征
词干提取(比如Porter Stemmer)会粗暴地将单词简化到词根,容易把语义不同的词合并成同一个形式,或者错误提取词干,丢失文本的区分度。比如"organization"和"organ"会被处理成同一个词根,完全扭曲语义。
解决:- 换成更温和的词形还原(Lemmatization)工具,比如WordNetLemmatizer,它会考虑单词的词性,保留更多语义信息;
- 暂时去掉词干提取步骤,测试精度变化,确认是不是这步的问题。
正则表达式过滤过度
你的正则规则把所有非数字、字母的字符都删除了,但在某些场景(比如社交媒体文本)中,@用户、#话题这类符号本身就是重要的分类特征,直接删除会损失关键信息。另外,正则里的^rt只匹配开头的rt,若rt出现在文本中间也可能有语义价值。
解决:- 调整正则表达式,只删除真正无意义的符号,保留对任务有价值的元素;
- 单独测试正则过滤步骤的影响,定位是否删了不该删的内容。
另外,建议把预处理步骤拆解开,每一步单独测试(比如先只做小写,看精度;再加正则,再加停用词,最后加词干),这样能精准定位是哪一步导致的精度下降。
内容的提问来源于stack exchange,提问作者Ben

