Tfidf
基本概念
所谓Tfidf,可以分为TF(词频, Term Frequency)和IDF(反文档频率, Inverse Document Frequency),然后二者相乘即可得到Tfidf.通俗的说,TF就是某个关键字出现的频率,DF是一个词在整个文库字典中出现的频率,IDF由DF进行运算得来.
TF的计算
N
i
,
j
=
n
i
,
j
∑
k
n
i
,
k
N_{i, j} = \frac{n_{i, j}}{\sum_{k}{n_{i,k}}}
Ni,j=∑kni,kni,j
其中:
- n i , j n_{i, j} ni,j表示词 j j j出现在文本 i i i中的次数
-
N
i
,
j
N_{i,j}
Ni,j表示词
j
j
j在文本
i
i
i中的词频
显然分子为句子中出现的某个词的个数,分母为词的总数。得到的矩阵为 N N N的 s h a p e shape shape为 ( n u m _ o f _ d o c m e n t s , v o c a b u l a r y ) (num\_of\_docments, vocabulary) (num_of_docments,vocabulary).如果我们只使用TF来作为文本的特征,势必会受到常用词的干扰,因此我们需要想方法惩罚常用词。
IDF的计算
I
D
F
j
=
l
o
g
∣
D
∣
D
j
+
1
IDF_j = log{\frac{|D|}{D_j+1}}
IDFj=logDj+1∣D∣
其中:
- I D F j IDF_j IDFj为词 j j j的反文档频率
- D j D_j Dj为包含词 j j j的文档个数
-
+
1
+1
+1是为了防止分母为
0
0
0
可见 I D F IDF IDF的 s h a p e shape shape为 ( v o c a b u l a r y , ) (vocabulary,) (vocabulary,).对于常用词,即使 T F i , j TF_{i,j} TFi,j的值很大,和 I D F j IDF_j IDFj相乘后也会变得很小。
TfidfVectorizer的使用
使用TfidfVectorizer可以把文本转换为tf-idf的特征矩阵,之后可以利用这个特征矩阵区进行文本相似度,LSA,文本搜索排序等任务.
from sklearn.feature_extraction.text import TfidfVectorizer
# 文本格式要求,中文需要使用分词工具预处理
document = ['我们 走 在 热闹 的 大街 上',
'当 我们 走到 街 中心 时',
'哪里 真是 人山人海',
'热闹非凡']
tfidf_model = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b", sublinear_tf=True, use_idf=True).fit(document)
# 得到的是一个类似于以三元组方式存储的稀疏矩阵,可以使用'.todense()'还原出原矩阵
sparse_result = tfidf_model.transform(document)
# 这一步可以得到一个词汇列表,可以使用索引还原出对应的词
print(tfidf_model.vocabulary_)
# 该方法可以得到所有的特征的名称列表
terms = tfidf.get_feature_names()
重要的参数:
token_pattern
: 默认为r"(?u)\b\w\w+\b"
,这是一个正则表达式,这里的两个w表示其需要匹配长度大于2的单词,因此中文中的单字单词会被忽略,可以通过去除第一个w来实现保留单个字的词语.对这个参数修改可以实现更多的要求,比如保留特殊符号等等.max_df/min_df
: 该参数可以为0到1之间的浮点数或者为正整数,默认值为1.0.如果为浮点数,就过滤掉超过max_df
比例的或者低于max_df
比例的句子中的词语.可以实现过滤掉一些无用的词.stop_words
: 接收list
类型的数据,如["是", "的"]
,过滤掉指定的停用词vocabulary
: 接收dict
类型的数据,只使用特定的词汇.可以设定感兴趣的词并且只考虑他们.如:{"我":0, "呀":1, "!":2}
TruncatedSVD
重要概念
TSVD将训练样本X转换为低维的近似等于
X
:
(
m
,
n
)
X:(m, n)
X:(m,n)矩阵的
X
k
X_k
Xk.
X
≈
X
k
=
U
k
Σ
k
V
k
T
X \approx X_k = U_k \Sigma_k V_k^T
X≈Xk=UkΣkVkT
其中,
U
k
:
(
m
,
k
)
U_k :(m, k)
Uk:(m,k),
Σ
k
:
(
k
,
k
)
\Sigma_k: (k, k)
Σk:(k,k),
V
k
:
(
n
,
k
)
V_k:(n, k)
Vk:(n,k),
X
k
:
(
m
,
n
)
X_k:(m, n)
Xk:(m,n)
而
X
V
:
(
m
,
k
)
XV:(m, k)
XV:(m,k)就是具有k个特征值的转换后的数据集。这里需要注意的一点是m代表样本数,n代表特征数,同理对行压缩则可以使用左奇异矩阵
U
T
X
:
(
k
,
n
)
U^TX:(k, n)
UTX:(k,n)。还有一点需要指出的是对列压缩即去掉相关性比较高列。
同理测试集转换可以直接使用
X
k
t
e
s
t
=
X
t
e
s
t
V
X_k^{test} = X^{test}V
Xktest=XtestV.
然而在实际情况中样本形状多为
(
f
e
a
t
u
r
e
s
,
s
a
m
p
l
e
s
)
(features, samples)
(features,samples),这就需要我们根据具体情况进行选择。
除此之外,TruncatedSVD 类似于PCA,不同的是TSVD直接处理样本矩阵
X
X
X,而不是
X
X
X的协方差矩阵
X
T
X
X^TX
XTX(数据标准化后的协方差矩阵)。注意到我们的SVD也可以得到协方差矩阵
X
T
X
X^TX
XTX最大的
d
d
d个特征向量张成的矩阵,但是SVD有个好处,有一些SVD的实现算法可以不先求出协方差矩阵
X
T
X
X^TX
XTX,也能求出我们的右奇异矩阵
V
V
V,如梯度下降法。也就是说,我们的PCA算法可以不用做特征分解(
X
T
X
X^TX
XTX是方阵,可以直接做特征值分解),而是做SVD来完成。这个方法在样本量很大的时候很有效。实际上,scikit-learn的PCA算法的背后真正的实现就是用的SVD,而不是我们我们认为的暴力特征分解。
更多的关于SVD的内容可以查看奇异值分解(SVD)原理与在降维中的应用.
TSVD的使用
上面一步的得到的矩阵大小为
(
∣
D
∣
,
∣
V
∣
)
(|D|, |V|)
(∣D∣,∣V∣),这一步我们将对它进行降维得到
(
∣
D
∣
,
∣
T
∣
)
(|D|, |T|)
(∣D∣,∣T∣).其中
∣
D
∣
|D|
∣D∣为文档个数,
∣
V
∣
|V|
∣V∣为单词个数,
∣
T
∣
|T|
∣T∣为SVD
降维后的主题个数。
n_pick_topics = 3 # 设定主题数为3
svd = TruncatedSVD(n_pick_topics)
X = svd.fit_transform(sparse_result)
对于一个特定行
X
[
d
,
:
]
X[d, :]
X[d,:]来说,最大的值对应的主题
t
m
a
x
t_{max}
tmax是这篇文档最有可能的主题;
对于一个特定列
X
[
:
,
t
]
X[:, t]
X[:,t]来说,最大的值对应的文档
d
m
a
x
d_{max}
dmax是最具备该主题的文档,也就是说文档
d
m
a
x
d_{max}
dmax在该主题上最具有代表性。
我们可以通过如下方法筛选出文档
d
m
a
x
d_{max}
dmax,该方法为每个主题筛选了两篇最具有代表性的文档。
n_pick_docs= 2
topic_docs_id = [X[:,t].argsort()[:-(n_pick_docs+1):-1] for t in range(n_pick_topics)]
除此之外,svd.components_
是一个大小为
(
∣
T
∣
,
∣
V
∣
)
(|T|, |V|)
(∣T∣,∣V∣),每一行为主题在每个单词上的分布。我们可以通过这个矩阵得到哪些词对主题t贡献最大。下面这段代码为每个主题选取了4个关键字。
n_pick_keywords = 4
topic_keywords_id = [svd.components_[t].argsort()[:-(n_pick_keywords+1):-1] for t in range(n_pick_topics)]
topic_keywords_id