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

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

常规使用

TfidfVectorizer可以把原始文本转化为tf-idf的特征矩阵,从而为后续的文本相似度计算,主题模型(如LSI),文本搜索排序等一系列应用奠定基础。基本应用如:

from sklearn.feature_extraction.text import TfidfVectorizer
document = ["I have a pen.",
            "I have an apple."]
tfidf_model = TfidfVectorizer().fit(document)
# 得到tf-idf矩阵,稀疏矩阵表示法
sparse_result = tfidf_model.transform(document)
print(sparse_result)
# 第0个字符串,对应词典序号为3的词的TFIDF为0.8148
# (0, 3)	0.814802474667
# (0, 2)	0.579738671538
# (1, 2)	0.449436416524
# (1, 1)	0.631667201738
# (1, 0)	0.631667201738
print(sparse_result.todense())
# 转化为更直观的一般矩阵
# [[ 0.          0.          0.57973867  0.81480247]
#  [ 0.6316672   0.6316672   0.44943642  0.        ]]
print(tfidf_model.vocabulary_)
# 词语与列的对应关系
# {'have': 2, 'pen': 3, 'an': 0, 'apple': 1}

注意:在上述计算tfidf过程中,有的词因为过于简短,会被自动丢弃,比如 I a 这两个词会被自动丢掉,这和

参数有关系,token_pattern。它默认只匹配长度>=2的单词。

中文使用:

分词

使用中文预料来统计tfidf

中文不比英文,词语之间有着空格的自然分割,所以我们首先要进行分词处理,再把它转化为与上面的document类似的格式。用著名的中文分词库jieba进行分词:

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)
# ['我 是 一条 天狗 呀 !', '我 把 月 来 吞 了 ,', '我 把 日来 吞 了 ,', '我 把 一切 的 星球 来 吞 了 ,', '我 把 全宇宙 来 吞 了 。', '我 便是 我 了 !']

建模

理论上,现在得到的document的格式已经可以直接拿来训练了。让我们跑一下模型试试。

tfidf_model = TfidfVectorizer().fit(document)
print(tfidf_model.vocabulary_)
# {'一条': 1, '天狗': 4, '日来': 5, '一切': 0, '星球': 6, '全宇宙': 3, '便是': 2}
sparse_result = tfidf_model.transform(document)
print(sparse_result)
# (0, 4)	0.707106781187
# (0, 1)	0.707106781187
# (2, 5)	1.0
# (3, 6)	0.707106781187
# (3, 0)	0.707106781187
# (4, 3)	1.0
# (5, 2)	1.0

注意:这里没有出现报错,但是我们发现,这里丢掉了一些词,是参数搞的怪,会自动丢掉过短的词。

参数

单字的问题是token_pattern这个参数搞的鬼。它的默认值只匹配长度≥2的单词,就像其实开头的例子中的'I'也被忽略了一样,一般来说,长度为1的单词在英文中一般是无足轻重的,但在中文里,就可能有一些很重要的单字词,所以修改如下:

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}

token_pattern这个参数使用正则表达式来分词,其默认参数为r"(?u)\b\w\w+\b",其中的两个\w决定了其匹配长度至少为2的单词,所以这边减到1个。对这个参数进行更多修改,可以满足其他要求,比如这里依然没有得到标点符号,在此不详解了。

过滤单词

  1. max_df/min_df: *[0.0, 1.0]内浮点数或正整数, 默认值=1.0* 当设置为浮点数时,过滤出现在超过max_df/低于min_df比例的句子中的词语;正整数时,则是超过max_df句句子。

    这样就可以帮助我们过滤掉出现太多的无意义词语,如下面的"我"就被过滤(虽然这里“我”的排比在文学上是很重要的)。

# 过滤出现在超过60%的句子中的词语
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}
  1. stop_words: *list类型* 直接过滤指定的停用词。
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}
  1. vocabulary: dict*类型*

只使用特定的词汇,其形式与上面看到的tfidf_model4.vocabulary_相同,也是指定对应关系。

​ 这一参数的使用有时能帮助我们专注于一些词语,比如我对本诗中表达感情的一些特定词语(甚至标点符号)感兴趣,就可以设定这一参数,只考虑他们:

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. ngram_range: tuple

有时候我们觉得单个的词语作为特征还不足够,能够加入一些词组更好,就可以设置这个参数,如下面允许词表使用1个词语,或者2个词语的组合:

​ 这里顺便使用了一个方便的方法 get_feature_names() ,可以以列表的形式得到所有的词语

tfidf_model5 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b", ngram_range=(1,2), stop_words=["是", "的"]).fit(document)
print(tfidf_model5.get_feature_names())
"""
['一切', '一切 星球', '一条', '一条 天狗', '了', '便是', '便是 我', '全宇宙', '全宇宙 来', '吞', '吞 了', '呀', '天狗', '天狗 呀', '我', '我 一条', '我 了', '我 便是', '我 把', '把', '把 一切', '把 全宇宙', '把 日来', '把 月', '日来', '日来 吞', '星球', '星球 来', '月', '月 来', '来', '来 吞']
"""
  1. max_feature: int

    在大规模语料上训练TFIDF会得到非常多的词语,如果再使用了上一个设置加入了词组,那么我们词表的大小就会爆炸。出于时间和空间效率的考虑,可以限制最多使用多少个词语,模型会优先选取词频高的词语留下。下面限制最多使用10个词语:

tfidf_model6 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b", max_features=10, ngram_range=(1,2), stop_words=["是", "的"]).fit(document)
print(tfidf_model6.vocabulary_)
"""
{'我': 3, '把': 5, '来': 8, '吞': 1, '了': 0, '我 把': 4, '来 吞': 9, '吞 了': 2, '日来 吞': 6, '星球': 7}
"""
比如这里大部分的词组都被过滤了,但是“我 把”因为多次出现而保留了。 

参考博客:

https://blog.csdn.net/blmoistawinde/article/details/80816179

posted @ 2020-08-31 15:48  胖墩哥  阅读(3889)  评论(0编辑  收藏  举报