词频-逆文档频率用于评估一个词对一个文档集或语料库的某个文档的重要程度,用于提取文档的关键词。

分词

中文不比英文,词语之间有着空格的自然分割。我们首先要进行中文的分词处理,使得分词之间产生空格。这里采用著名的中文分词库jieba进行分词:

1
2
3
4
5
6
7
8
9
10
11
12
import jieba
text = """我是一条天狗呀!
我把月来吞了,
我把日来吞了,
我把一切的星球来吞了,
我把全宇宙来吞了。
我便是我了!"""
sentences = text.split()
sent_words = [list(jieba.cut(sent0)) for sent0 in sentences]
document = [" ".join(sent0) for sent0 in sent_words]
print(document)
# ['我 是 一条 天狗 呀 !', '我 把 月 来 吞 了 ,', '我 把 日来 吞 了 ,', '我 把 一切 的 星球 来 吞 了 ,', '我 把 全宇宙 来 吞 了 。', '我 便是 我 了 !']

TfidfVectorizer的参数说明

token_pattern

说明词汇表的入选单词的模式,默认值为r'(?u)\b\w\w+\b',匹配从开始到结尾至少两个字符的字符串为词汇表的入选单词(\b匹配单词的开始或结束,\w匹配字母或数字或下划线或汉字,参考链接:正则表达式30分钟入门教程),如果想让词汇表中出现一个字符的单词,应如下赋值。

1
2
3
4
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_model2 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b").fit(document)
print(tfidf_model2.vocabulary_)
# {'我': 8, '是': 12, '一条': 1, '天狗': 7, '呀': 6, '把': 9, '月': 13, '来': 14, '吞': 5, '了': 2, '日来': 10, '一切': 0, '的': 15, '星球': 11, '全宇宙': 4, '便是': 3}

max_df/min_df

规定包含某词汇表的单词的文档频率的最大值或最小值,0-1的小数表示比例,整数表示包含该单词的最大或最小文档数量。不在文档频率范围内的单词不会进入词汇表。

1
2
3
tfidf_model3 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b", max_df=0.6).fit(document)  
print(tfidf_model3.vocabulary_)
# {'是': 8, '一条': 1, '天狗': 5, '呀': 4, '月': 9, '来': 10, '日来': 6, '一切': 0, '的': 11, '星球': 7, '全宇宙': 3, '便 是': 2}

比如“我”这个单词的文档频率为6/6=1,大于0.6,故不会进入词汇表

stop_words

表示不需要加入词汇表的语气词或连词

1
2
3
tfidf_model4 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b", max_df=0.6, stop_words=["是", "的"]).fit(document)
print(tfidf_model4.vocabulary_)
# {'一条': 1, '天狗': 5, '呀': 4, '月': 8, '来': 9, '日来': 6, '一切': 0, '星球': 7, '全宇宙': 3, '便是': 2}

“是”和“的”没有进入词汇表

vocabulary

直接设定词汇表

1
2
3
4
5
6
7
8
9
10
tfidf_model5 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b",vocabulary={"我":0, "呀":1,"!":2}).fit(document)
print(tfidf_model5.vocabulary_)
# {'我': 0, '呀': 1, '!': 2}
print(tfidf_model5.transform(document).todense())
# [[0.40572238 0.91399636 0. ]
# [1. 0. 0. ]
# [1. 0. 0. ]
# [1. 0. 0. ]
# [1. 0. 0. ]
# [1. 0. 0. ]]

tfidf(词频逆文档频率)计算方式:tfidf=tf*ln(D/(d+1)),D表示文档总数,d表示包含单词的文档数量,比如除了第一句,其余句子的“呀”的tfidf都是0,因为呀在其他句子里的词频都为0,呀在第一句中的词频是1/5=0.2,逆文频=ln(6/2)=1.1,乘起来等于0.55,我在第一句中的词频=1/5=0.2,逆文频=ln(6/7)=-0.15,乘起来等于-0.075(ln函数的计算方式:import numpy as np;y=np.log(x)),感叹号不会被TfidfVectorizer处理,所以感叹号的tfidf为0,很明显0.4^2+0.91^2约等于1,即TfidfVectorizer向量化后的都是标准化向量。但我之前算的(-0.075,0.55,0)标准化后为(0.14,0.99,0),(0.075*(math.sqrt(1/(0.075**2+0.55**2)))=0.13511320473331348, 0.55*(math.sqrt(1/(0.075**2+0.55**2)))=0.9908301680442989

ngram_range

表示单词的多种组合也能进入词汇表

1
2
3
4
5
6
7
tfidf_model6 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b", ngram_range=(1,2), stop_words=["是", "的"]).fit(document)
print(tfidf_model6.get_feature_names_out())
print(tfidf_model6.vocabulary_)
# ['一切' '一切 星球' '一条' '一条 天狗' '了' '便是' '便是 我' '全 宇宙' '全宇宙 来' '吞' '吞 了' '呀'
# '天狗' '天狗 呀' '我' '我 一条' '我 了' '我 便是' '我 把' '把' '把 一切' '把 全宇宙' '把 日来' '把 月'
# '日来' '日来 吞' '星球' '星球 来' '月' '月 来' '来' '来 吞']
# {'我': 14, '一条': 2, '天狗': 12, '呀': 11, '我 一条': 15, '一条 天狗': 3, '天狗 呀': 13, '把': 19, '月': 28, '来': 30, '吞': 9, '了': 4, '我 把': 18, '把 月': 23, '月 来': 29, '来 吞': 31, '吞 了': 10, '日来': 24, '把 日来': 22, '日来 吞': 25, '一切': 0, '星球': 26, '把 一切': 20, '一切 星球': 1, '星球 来': 27, '全宇宙': 7, '把 全宇宙': 21, '全宇宙 来': 8, '便是': 5, '我 便是': 17, '便是 我': 6, '我 了': 16}

max_feature

限制使用词频top高的单词组成词汇表

1
2
3
tfidf_model7 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b", max_features=10, ngram_range=(1,2), stop_words=["是", "的"]).fit(document)
print(tfidf_model7.vocabulary_)
# {'我': 3, '把': 5, '来': 8, '吞': 1, '了': 0, '我 把': 4, '来 吞': 9, '吞 了': 2, '日来 吞': 6, '星球': 7}

参考链接:sklearn: TfidfVectorizer 中文处理及一些使用参数

TF-IDF(词频-逆文档频率)介绍

创建于2023.2.13/0.20,修改于2023.3.15/15.27