先把数据“理干净”:预处理是分类的地基
做文本分类前,你拿到的 raw data 可能像没整理的衣柜——满是广告水印、乱码、重复内容。这一步的核心是“把无关信息删掉,把有用信息标准化”。

1. 数据清洗:去掉“噪音”
先处理明显的垃圾:比如网页爬取的文本里的[广告]
、点击查看
,或者用户输入的@#¥%
乱码。用正则表达式一键解决:
import re
def clean_text(text):
# 去掉特殊符号和数字
text = re.sub(r'[^u4e00-u9fa5a-zA-Z]', ' ', text)
# 去掉多余空格
text = re.sub(r's+', ' ', text).strip()
return text
# 示例:把"我买了10斤苹果![广告]好吃到哭😭"变成"我买了斤苹果 好吃到哭"
2. 分词:把句子拆成“词块”
中文和英文的分词逻辑不一样——英文用空格分隔,中文得用工具。常用的工具有:
– 中文:jieba(Python)、HanLP(Java)
– 英文:NLTK(Python)、SpaCy(多语言)
给你个jieba分词的实用代码,能自动识别英文单词(比如“Python”不会被拆成“P y t h o n”):
import jieba
jieba.add_word("Python") # 自定义词典,避免英文被拆分
def cut_chinese(text):
return [word for word in jieba.cut(text) if len(word) > 1] # 过滤单字
# 示例:"我用Python做NLP文本分类" → ["用", "Python", "做", "NLP", "文本分类"]
3. 停用词:把“没用的词”删掉
像“的、地、得”“a、the、and”这些词,对分类没帮助,反而增加计算量。给你一份通用停用词表(部分):
| 中文停用词 | 英文停用词 |
|————|————|
| 的、地、得 | a、the、and|
| 是、了、啊 | is、are、was|
| 这、那、哦 | of、for、with|
用Python过滤停用词的代码:
stopwords = set(open("stopwords.txt", "r", encoding="utf-8").read().splitlines())
def remove_stopwords(words):
return [word for word in words if word not in stopwords]
4. 标准化:让文本“统一格式”
– 小写化:把“PYTHON”变成“python”(避免大小写导致的重复)
– 去标点:用string.punctuation
去掉!@#$%^&*()
– 还原词形:英文用NLTK的PorterStemmer
(比如“running”→“run”)
从文字到数字:特征工程是分类的桥梁
计算机不懂文字,只懂数字。这一步要把“我喜欢苹果”变成[0.1, 0.8, 0.3]
这样的向量——这就是特征工程。
1. 传统特征:简单但好用
– 词袋模型(Bag of Words):统计每个词出现的次数。比如“我喜欢苹果,我讨厌香蕉”→{"我":2, "喜欢":1, "苹果":1, "讨厌":1, "香蕉":1}
。
– TF-IDF:比词袋模型更聪明——不仅看词出现的次数,还看它在所有文档中出现的频率(比如“的”出现很多,但TF-IDF值很低)。
用sklearn做TF-IDF的代码:
from sklearn.feature_extraction.text import TfidfVectorizer
# 示例文本
texts = ["我喜欢苹果", "我讨厌香蕉", "苹果好吃", "香蕉难吃"]
# 初始化TF-IDF
tfidf = TfidfVectorizer()
# 生成特征矩阵
features = tfidf.fit_transform(texts)
# 查看特征词和权重
print(tfidf.get_feature_names_out()) # ["苹果", "喜欢", "讨厌", "好吃", "香蕉", "难吃"]
print(features.toarray()) # 每行是一个文本的TF-IDF向量
2. 深度学习特征:让模型“理解语义”
传统特征忽略了“词序”和“语义”——比如“我喜欢苹果”和“苹果喜欢我”的词袋向量一样,但意思完全相反。这时候需要词嵌入(Word Embedding):把每个词变成一个固定长度的向量,相似的词向量更接近(比如“苹果”和“香蕉”的向量距离比“苹果”和“汽车”近)。
常用的词嵌入模型:
– Word2Vec(Google):用“预测相邻词”的方法训练
– GloVe(斯坦福):结合“全局统计”和“局部上下文”
– FastText(Facebook):能识别词缀(比如“cat”和“cats”的向量更接近)
用Gensim加载预训练Word2Vec模型的代码:
from gensim.models import KeyedVectors
# 加载预训练模型(需要先下载:https://code.google.com/archive/p/word2vec/)
model = KeyedVectors.load_word2vec_format("GoogleNews-vectors-negative300.bin", binary=True)
# 查看“apple”的向量
print(model["apple"].shape) # (300,)
# 找相似词
print(model.most_similar("apple", topn=3)) # [("banana", 0.72), ("orange", 0.68), ("pear", 0.65)]
选对模型:不同场景用不同“武器”
特征准备好了,接下来选模型。给你一张“模型选择地图”,照着选绝对不踩坑:
小数据集(<1000条):用“轻量级模型”
朴素贝叶斯(Naive Bayes):速度快、准确率高,适合短文本(比如垃圾邮件分类、情感分析)。
给你个用朴素贝叶斯做情感分析的代码:
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score
# 训练数据(正面:1,负面:0)
X_train = ["我喜欢这个产品", "这个产品太烂了", "质量很好", "服务很差"]
y_train = [1, 0, 1, 0]
# 特征工程(TF-IDF)
tfidf = TfidfVectorizer()
X_train_vec = tfidf.fit_transform(X_train)
# 训练模型
nb_model = MultinomialNB()
nb_model.fit(X_train_vec, y_train)
# 测试数据
X_test = ["这个产品不错", "服务太糟糕了"]
X_test_vec = tfidf.transform(X_test)
# 预测
y_pred = nb_model.predict(X_test_vec)
print(accuracy_score([1,0], y_pred)) # 输出1.0(全对)
中数据集(1000-10000条):用“平衡型模型”
支持向量机(SVM):擅长处理高维特征(比如TF-IDF向量),适合文本分类、垃圾邮件过滤。
CNN(卷积神经网络):用“卷积层”捕捉局部特征(比如“不好吃”这个短语),适合短文本(比如微博内容)。
给你个用Keras搭CNN模型的代码:
from keras.models import Sequential
from keras.layers import Embedding, Conv1D, GlobalMaxPooling1D, Dense
from keras.preprocessing.sequence import pad_sequences
from keras.preprocessing.text import Tokenizer
# 1. 准备数据
texts = ["我喜欢这个电影", "这个电影太无聊了", "剧情很精彩", "演员演技差"]
labels = [1, 0, 1, 0]
# 2. tokenizer(把词变成索引)
tokenizer = Tokenizer(num_words=1000)
tokenizer.fit_on_texts(texts)
X = tokenizer.texts_to_sequences(texts)
# 3. 填充序列(让所有文本长度一致)
X = pad_sequences(X, maxlen=10)
# 4. 搭CNN模型
model = Sequential()
model.add(Embedding(input_dim=1000, output_dim=128, input_length=10)) # 词嵌入层
model.add(Conv1D(filters=64, kernel_size=3, activation='relu')) # 卷积层(捕捉3-gram特征)
model.add(GlobalMaxPooling1D()) # 全局池化层(把卷积结果压缩成一个向量)
model.add(Dense(1, activation='sigmoid')) # 输出层(二分类)
# 5. 编译模型
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# 6. 训练
model.fit(X, labels, epochs=10, batch_size=2)
大数据集(>10000条):用“语义型模型”
BERT(Google):2019年推出的“里程碑模型”,用“双向Transformer”捕捉上下文语义(比如“苹果”在“我吃苹果”和“苹果手机”中的向量不同)。
RoBERTa(Facebook):BERT的优化版,用“动态掩码”和“更大的 batch size”训练,效果更好。
DistilBERT(Hugging Face):BERT的“轻量版”,体积小一半,速度快两倍,准确率只降1-2%(适合部署到手机或服务器)。
用Hugging Face Transformers库加载BERT做分类的代码:
from transformers import BertTokenizer, TFBertForSequenceClassification
import tensorflow as tf
# 1. 加载预训练模型和tokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-chinese")
model = TFBertForSequenceClassification.from_pretrained("bert-base-chinese", num_labels=2)
# 2. 准备数据
texts = ["我喜欢这个产品", "这个产品太烂了"]
labels = [1, 0]
# 3. tokenize(把文本变成BERT需要的输入格式:input_ids、attention_mask)
inputs = tokenizer(texts, padding=True, truncation=True, max_length=512, return_tensors="tf")
# 4. 编译模型
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=2e-5), loss=model.hf_compute_loss, metrics=['accuracy'])
# 5. 训练
model.fit(dict(inputs), labels, epochs=3, batch_size=2)
踩过的坑:这些错误别再犯!
我做文本分类时踩过很多坑,给你避避雷:
1. 数据 imbalance:比如90%是正面样本,10%是负面样本,模型会偏向预测正面。解决方法:
– 过采样:复制少数类样本(用SMOTE工具)
– 欠采样:删除多数类样本
– 调整class weight:给少数类更高的权重(比如class_weight={0:9, 1:1}
)
2. 过拟合:模型在训练集上准确率99%,测试集上只有70%。解决方法:
– 增加数据量(用数据增强:同义词替换、回译)
– 正则化:给模型加L1/L2正则(比如SVC(C=0.1)
)
– Dropout:在神经网络中随机关闭部分神经元(比如model.add(Dropout(0.5))
)
3. 特征维度爆炸:比如用TF-IDF处理10万条文本,特征维度会达到10万+,计算很慢。解决方法:
– 特征选择:用Chi-square测试选“和分类相关的特征”
– 降维:用PCA把高维特征压缩成低维(比如PCA(n_components=1000)
)
从代码到产品:模型部署的最后一公里
训练好模型,要让它“能用”——比如做个API,让用户输入文本就能得到分类结果。给你个用FastAPI部署朴素贝叶斯模型的代码:
from fastapi import FastAPI
import pickle
import jieba
# 1. 加载模型和tokenizer
with open("text_classifier.pkl", "rb") as f:
model, vectorizer = pickle.load(f)
# 2. 初始化FastAPI
app = FastAPI()
# 3. 定义预处理函数
def preprocess(text):
text = clean_text(text) # 之前写的清洗函数
words = cut_chinese(text) # 之前写的分词函数
words = remove_stopwords(words) # 之前写的去停用词函数
return " ".join(words)
# 4. 定义API接口
@app.post("/classify")
def classify(text: str):
# 预处理
processed_text = preprocess(text)
# 特征转换
features = vectorizer.transform([processed_text])
# 预测
prediction = model.predict(features)[0]
# 返回结果
return {
"text": text,
"processed_text": processed_text,
"prediction": "正面" if prediction == 1 else "负面"
}
# 运行:uvicorn main:app --reload(在终端输入)
用Postman测试API:
– 请求方法:POST
– 请求URL:http://127.0.0.1:8000/classify
– 请求体:{"text": "这个产品太好用了"}
– 返回结果:{"text":"这个产品太好用了","processed_text":"产品 好用","prediction":"正面"}
原创文章,作者:,如若转载,请注明出处:https://zube.cn/archives/213