自从开始做自然语言处理的业务,TF-IDF就是使用很频繁的文本特征技术,他的优点很多,比如:容易理解,不需要训练,提取效果好,可以给予大规模数据使用,总之用的很顺手,但是人无千面好,花无百日红,TF-IDF也有一些局限的地方,这次我们聊聊忽略词序的问题和解决的思路。
忽略词序
TF-IDF主要是计算词频和逆向词频了计算文本特征的(一个词在文档中出现的频率越高(TF),同时在所有文档中出现的频率越低(IDF),则该词对当前文档的代表性越强。),那么对于词的位置(就是词的顺序)实际上考虑的不多,但是中文当中,词的位置可能导致反转的效果,网上最多的举例就是:‘人咬狗’和‘狗咬人’。那么这样就导致了忽略词序的问题。
解决思路
一、基础改进方法
1. N-gram特征扩展
思路:将相邻词的组合作为新特征
from sklearn.feature_extraction.text import TfidfVectorizer # 使用二元语法(bigram) vectorizer = TfidfVectorizer(ngram_range=(1, 2)) # 同时包含unigram和bigram
优点:
-
简单直接,兼容现有TF-IDF流程
-
能捕获局部词序关系
缺点:
-
特征空间爆炸(n越大,维度越高)
-
仍无法捕获长距离依赖
2. 滑动窗口加权
思路:给窗口内的词对添加位置权重
from collections import defaultdict def sliding_window_tfidf(docs, window_size=3):# 先计算普通TF-IDF# 然后为窗口内的词对添加额外权重co_occur = defaultdict(float)for doc in docs:words = doc.split()for i in range(len(words)-window_size+1):window = words[i:i+window_size]for j in range(len(window)):for k in range(j+1, len(window)):pair = (window[j], window[k])co_occur[pair] += 1# 将共现信息融入TF-IDF权重
二、进阶混合方法
3. TF-IDF与词嵌入结合
思路:用词向量补充语义信息
import numpy as np from gensim.models import Word2Vec # 训练或加载词向量模型 w2v_model = Word2Vec(sentences, vector_size=100, window=5, min_count=1) def enhanced_tfidf(doc):words = doc.split()tfidf_vec = tfidf_model.transform([doc]) # 常规TF-IDFw2v_vec = np.mean([w2v_model.wv[word] for word in words if word in w2v_model.wv], axis=0)return np.concatenate([tfidf_vec.toarray()[0], w2v_vec]) # 拼接两种特征
4. 短语检测预处理
思路:先识别固定短语再计算TF-IDF
from gensim.models.phrases import Phrases # 自动检测常见短语 phrases = Phrases(sentences) doc_with_phrases = ["_".join(words) for words in phrases[sentences]] # 然后在这些处理后的文本上计算TF-IDF
三、最新预训练模型方法
5. BERT + TF-IDF混合
思路:结合上下文嵌入与传统特征
from transformers import BertTokenizer, TFBertModel import tensorflow as tf bert_model = TFBertModel.from_pretrained('bert-base-chinese') tokenizer = BertTokenizer.from_pretrained('bert-base-chinese') def get_bert_tfidf_features(text):# BERT特征inputs = tokenizer(text, return_tensors="tf", truncation=True, padding=True)outputs = bert_model(**inputs)bert_features = tf.reduce_mean(outputs.last_hidden_state, axis=1)# TF-IDF特征tfidf_features = tfidf_vectorizer.transform([text])# 合并特征return tf.concat([bert_features, tfidf_features.toarray()], axis=1)
四、设想
-
评估指标选择:
-
对于分类任务:准确率/F1值
-
对于检索任务:MAP/MRR/NDCG
-
计算开销:特征维度/推理时间
-
-
实施路线图:
-
资源权衡:
-
低资源环境:N-gram + 短语检测
-
中等资源:TF-IDF + 词嵌入
-
充足资源:BERT/Transformer混合模型
-
当然还有很多方法,比如基于RNN也可以解决,由于篇幅就不在列举了,欢迎各位给出跟多的方法大家一起交流。上面的这些方法可以根据具体场景组合使用,例如先进行短语检测,再使用N-gram扩展,最后与词向量特征拼接,能在多个层面上改善原始TF-IDF忽略词序的问题。