1. CountVectorizer
CountVectorizer
类会将文本中的词语转换为词频矩阵。
例如矩阵中包含一个元素,它表示词在类文本下的词频。它通过fit_transform
函数计算各个词语出现的次数,通过get_feature_names()
可获取词袋中所有文本的关键字,通过toarray()
可看到词频矩阵的结果。
from sklearn.feature_extraction.text import CountVectorizer
#语料
corpus = [
'This is the first document.',
'This is the this second second document.',
'And the third one.',
'Is this the first document?'
]
#将文本中的词转换成词频矩阵
vectorizer = CountVectorizer()
print(vectorizer)
#计算某个词出现的次数
X = vectorizer.fit_transform(corpus)
print(type(X),X)
#获取词袋中所有文本关键词
word = vectorizer.get_feature_names()
print(word)
#查看词频结果
print(X.toarray())
结果:
(0, 2) 1
(0, 6) 1
(0, 3) 1
(0, 8) 1
(1, 5) 2
(1, 1) 1
(1, 6) 1
(1, 3) 1
(1, 8) 2
(2, 4) 1
(2, 7) 1
(2, 0) 1
(2, 6) 1
(3, 1) 1
(3, 2) 1
(3, 6) 1
(3, 3) 1
(3, 8) 1
['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']
[[0 1 1 1 0 0 1 0 1]
[0 1 0 1 0 2 1 0 2]
[1 0 0 0 1 0 1 1 0]
[0 1 1 1 0 0 1 0 1]]
2. TF-IDF
TF-IDF(term frequency-inverse document frequency)是文本加权方法,采用统计思想,即文本出现的次数和整个语料中文档频率来计算字词的重要度。
优点:过滤一些常见但是无关紧要的字词。
TF(Term Frequency)表示某个关键词在整篇文章中出现的频率。(某个词在文章中出现的总次数/文章的总词数);
IDF(Inverse Document Frequency)表示计算倒文本频率。文本频率是指某个关键词在整个语料所有文章中出现的次数。倒文档频率又称为逆文档频率,它是文档频率的倒数,主要用于降低所有文档中一些常见却对文档影响不大的词语的作用。
默认:
这里, 为总的文档数, 为包含这个词
教科书标准的idf定义:
其中, 代表语料库的文档总数; 代表包含该词的文档数.
Tfidf 实现,一般是先通过countVectorizer
, 然后再通过 tfidfTransformer
, 转换成 tfidf
向量; 也有现成的 TfidfVectorizer
API。
语句:
TfidfTransformer(norm='l2', use_idf=True, smooth_idf=True, sublinear_tf=False)
示例:
from sklearn.feature_extraction.text import TfidfVectorizer, TfidfTransformer, CountVectorizer
import numpy as np
#语料
cc = [
'aa bb.',
'aa cc.'
]
# method 1
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(cc)
print('feature',vectorizer.get_feature_names())
print(X.toarray())
结果:
feature ['aa', 'bb', 'cc']
[[0.57973867 0.81480247 0. ]
[0.57973867 0. 0.81480247]]
值得注意的是,默认语料会把单个字符当作停止单词(stop_words)进行过滤,如果需要保留单个字符组成的单词,可以修改分词方式:token_pattern='(?u)\\b\\w+\\b'
此外,上面还可实现如下:
# method 2
vectorizer=CountVectorizer()#token_pattern='(?u)\\b\\w+\\b'
transformer = TfidfTransformer()
cntTf = vectorizer.fit_transform(cc)
print('feature', vectorizer.get_feature_names())
print(cntTf)
cnt_array = cntTf.toarray()
X = transformer.fit_transform(cntTf)
print(X.toarray())
结果:
feature ['aa', 'bb', 'cc']
# 第一个数字表示第几个文档;第二个数字表示第几个feature,结果表示相应的词频。
(0, 1) 1
(0, 0) 1
(1, 2) 1
(1, 0) 1
[[0.57973867 0.81480247 0. ]
[0.57973867 0. 0.81480247]]
为了更加明白TfidfTransformer
的操作,进行简单分解实现该功能:
# method 3
vectorizer=CountVectorizer()
cntTf = vectorizer.fit_transform(cc)
tf = cnt_array/np.sum(cnt_array, axis = 1, keepdims = True)
print('tf',tf)
idf = np.log((1+len(cnt_array))/(1+np.sum(cnt_array,axis = 0))) + 1
print('idf', idf)
t = tf*idf
print('tfidf',t)
print('norm tfidf', t/np.sqrt(np.sum(t**2, axis = 1, keepdims=True)))
结果:
tf [[0.5 0.5 0. ]
[0.5 0. 0.5]]
idf [1. 1.40546511 1.40546511]
tfidf [[0.5 0.70273255 0. ]
[0.5 0. 0.70273255]]
norm tfidf [[0.57973867 0.81480247 0. ]
[0.57973867 0. 0.81480247]]
也就是说,TfidfTransformer
默认会对获得的向量除以2范数进行归一化。
TF-IDF的信息论依据
一个查询(Query)中的每个关键词(Key Word)w的权重应该反映这个词查询来讲提供了多少信息。一个简单方法是用每个词的信息量作为他的权重。
但是,如果两个词出现的频率 TF相同, 一个是某篇特定文章中的常见词,而另外一个词时分散在多篇文章中,显然第一个词有更高的分辨率,权重应该更大。
3. HashingVectorizer
语法
HashingVectorizer(alternate_sign=True, analyzer='word', binary=False,
decode_error='strict', dtype=<class 'numpy.float64'>,
encoding='utf-8', input='content', lowercase=True,
n_features=1048576, ngram_range=(1, 1), non_negative=False,
norm='l2', preprocessor=None, stop_words=None, strip_accents=None,
token_pattern='(?u)\\b\\w\\w+\\b', tokenizer=None)
特点
普通的CountVectorizer存在但词库很大时,占用大内存,因此,使用hash技巧,并用稀疏矩阵存储编译后的矩阵,能很好解决这个问题。
实现的伪代码为:
function hashing_vectorizer(features : array of string, N : integer):
x := new vector[N]
for f in features:
h := hash(f)
x[h mod N] += 1
return x
这里伪代码没有考虑到hash
冲突的情况,实际实现会更加复杂。
from sklearn.feature_extraction.text import HashingVectorizer
corpus = [
'This is the first document.',
'This document is the second document.',
'And this is the third one.',
'Is this the first document?',
]
vectorizer = HashingVectorizer(n_features=2**4)
X = vectorizer.fit_transform(corpus)
print(X.toarray())
print(X.shape)
结果:
[[-0.57735027 0. 0. 0. 0. 0.
0. 0. -0.57735027 0. 0. 0.
0. 0.57735027 0. 0. ]
[-0.81649658 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.40824829
0. 0.40824829 0. 0. ]
[ 0. 0. 0. 0. -0.70710678 0.70710678
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. ]
[-0.57735027 0. 0. 0. 0. 0.
0. 0. -0.57735027 0. 0. 0.
0. 0.57735027 0. 0. ]]
(4, 16)
4. 总结
总的而言,这三种都是词袋模型的方法,其中,由于tfidfvectorizer
这种方法可以降低高频信息量少词语的干扰,应用得更多。