在自然语言处理中, 词袋模型是一种常用的处理文本信息的模型.
我们拿到一段文本信号后, 首先应该进行分词以得到一个个 token, 然后将这些 token 用向量表示出来再送入机器学习模型中进行训练. 词袋模型和 TF-IDF 就是一种将 token 转变成向量的方法.
词袋模型: 首先定义一些特殊的标记词, 统计这些标记词在文本中出现的次数, 将这些数字组成一个向量来代表文本.
如上图所示, 有三个文本, 分别是 "good movie","not a good movie" 和 "did not like", 选择 good,movie,not, a,did 和 like 作为 6 个标记词, 统计这 6 个词在文本中出现的次数, 得到一个如右边表格所示的矩阵, 每一行组成的向量代表一个文本.
这样得到了一个将文本转化成向量的模型, 这样的模型有两个缺点:
丢失了词的顺序特征
产生的向量是非标准化的
在文本信息中, 词的顺序会影响语义的判断, 因此丢失了文本中词的顺序特征会造成识别的准确率下降. 因此引入 n-grams 的概念.
在上面的模型中, 选取的标记词都是一个单字, 如果标记词中包含词组 (比如包含两个, 三个或者 n 个单字), 那么这样的模型就可以在一定程度上弥补丢失的词的顺序这个缺点, 这种方法我们成为 n-grams.
n-grams
如图, 标记词中加入了两个单词组成的词组, 这样重新得到一个矩阵, 同样每一行代表一条文本信息.
缺点: 当文本过大时会导致过多的特征.
解决方法: 剔除一些用处不大的 n-grams.
出现频率过高的 n-grams. 比如英语中的 a, the 这种对于识别没有用处的冠词, 出现频率又极高, 可以剔除
出现频率过低的 n-grams. 比如错别字等, 如果模型也考虑了这种词汇可能会导致过拟合.
保留二者之间频率的 n-grams.
接下来问题就变成了如何处理出现频率中等的 n-grams:
思路: 同样依据出现频率来进行筛选. 比如出现频率比较低的往往对于不同的文本有较好的区分度. 于是引入 TF-IDF 指标.
TF(Term Frequency, 词频):tf ( t, d ) 表示 n-grams 在文本 d 中出现的频次.
计算方法有多种:
TF 计算方法
IDF(Inverse document frequency, 逆文本频率指数):
N = |D|, 语料库中所有文本的总数
|{dD:td}|, 有 n-gram t 出现的所有文本的总和
idf(t,D) = log(N/|{dD:td}|)
也就是说, 如果 n-grams 在很多个文档中都出现, 那么 idf 值计算出来就很小 (最极端的情况, 在所有文档中都出现, 则 idf 值为 0), 这种情况下可以认为这个 n-grams 对不同文本的区分能力很差.
tfidf(t,d,D)=tf(t,d).idf(t,D) , 为两个指标之积, 那些在一个文本中出现频次高但是很少在其他文本中出现的词被认为对该文本具有很好的区分度, 而这样的词就会有一个比较高的 TF-IDF 值.
总结:
用 TF-IDF 值来替代词袋模型简单的计数值
对每个向量进行标准化
词袋模型与 TF-IDF 指标得到的文本表示 (进行了 L2 标准化)
最后是 python 代码举例:
- from sklearn.feature_extraction.text import TfidfVectorizer
- import pandas as pd
- text = {"good movie", "not a good movie", "did not like",
- "i like it", "good one"}
- tfidf = TfidfVectorizer(min_df=2, max_df=0.5, ngram_range=(1, 2))
- features = tfidf.fit_transform(texts)
- pd.DataFrame(
- features.todense(),
- columns=tfidf.get_feature_names()
- )
运行结果
来源: https://www.qcloud.com/developer/article/1158516