gpt4 book ai didi

python - 如何从 SKLearn 的 TfidfVectorizer 手动计算 TF-IDF 分数

转载 作者:行者123 更新时间:2023-12-02 07:45:09 26 4
gpt4 key购买 nike

我一直在运行 SKLearn 的 TF-IDF Vectorizer,但在手动重新创建值时遇到问题(以帮助理解正在发生的情况)。

为了添加一些上下文,我有一个文档列表,我从中提取了命名实体(在我的实际数据中,这些实体最多为 5 克,但在这里我将其限制为二元)。我只想知道这些值的 TF-IDF 分数,并认为通过 vocabulary 参数传递这些术语就可以做到这一点。

这里有一些与我正在使用的类似的虚拟数据:

from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd


# list of named entities I want to generate TF-IDF scores for
named_ents = ['boston','america','france','paris','san francisco']

# my list of documents
docs = ['i have never been to boston',
'boston is in america',
'paris is the capitol city of france',
'this sentence has no named entities included',
'i have been to san francisco and paris']

# find the max nGram in the named entity vocabulary
ne_vocab_split = [len(word.split()) for word in named_ents]
max_ngram = max(ne_vocab_split)

tfidf = TfidfVectorizer(vocabulary = named_ents, stop_words = None, ngram_range=(1,max_ngram))
tfidf_vector = tfidf.fit_transform(docs)

output = pd.DataFrame(tfidf_vector.T.todense(), index=named_ents, columns=docs)

注意:我知道默认情况下会删除停用词,但我的实际数据集中的一些命名实体包含诸如“国家部门”之类的短语。所以他们就一直被留在这里。

这是我需要帮助的地方。据我了解,我们计算 TF-IDF 的方式如下:

TF: 术语频率:根据 SKlearn guidelines是“某个术语在给定文档中出现的次数”

IDF:逆文档频率:1+文档数与1+包含该词的文档数之比的自然对数。根据链接中的相同准则,结果值添加了 1,以防止被零除。

然后,我们将 TF 乘以 IDF,得出给定文档中给定术语的总体 TF-IDF

示例

让我们以第一列为例,它只有一个命名实体“Boston”,根据上面的代码,第一个文档 1 上有一个 TF-IDF。但是,当我手动计算出来时,我得到以下内容:

TF = 1

IDF = log-e(1+total docs / 1+docs with 'boston') + 1
' ' = log-e(1+5 / 1+2) + 1
' ' = log-e(6 / 3) + 1
' ' = log-e(2) + 1
' ' = 0.69314 + 1
' ' = 1.69314

TF-IDF = 1 * 1.69314 = 1.69314 (not 1)

也许我在文档中遗漏了一些内容,说明分数上限为 1,但我无法找出哪里出了问题。此外,通过上述计算,波士顿在第一列和第二列中的分数不应该有任何差异,因为该术语在每个文档中仅出现一次。

编辑发布问题后,我认为术语频率可能是与文档中的一元组数或文档中的命名实体数的比率来计算的。例如,在第二个文档中,SKlearn 为波士顿生成的分数为 0.627914。如果我将 TF 计算为 tokens = 'boston' (1) : all unigram tokens (4) 的比率,我会得到 0.25 的 TF,当我应用于 TF-IDF 时会返回一个分数刚刚超过 0.147

类似地,当我使用 token = 'boston' (1) : 所有 NE token (2) 的比率并应用 TF-IDF 时,我得到的分数为 0.846。很明显我在某个地方出错了。

最佳答案

让我们一步一步地进行这个数学练习。

第 1 步:获取 boston token 的 tfidf 分数

docs = ['i have never been to boston',
'boston is in america',
'paris is the capitol city of france',
'this sentence has no named entities included',
'i have been to san francisco and paris']

from sklearn.feature_extraction.text import TfidfVectorizer

# I did not include your named_ents here but did for a full vocab
tfidf = TfidfVectorizer(smooth_idf=True,norm='l1')

注意TfidfVectorizer中的参数,它们对于稍后的平滑和标准化很重要。

docs_tfidf = tfidf.fit_transform(docs).todense()
n = tfidf.vocabulary_["boston"]
docs_tfidf[:,n]
matrix([[0.19085885],
[0.22326669],
[0. ],
[0. ],
[0. ]])

到目前为止,我们得到的是 boston 标记的 tfidf 分数(词汇中的#3)。

第 2 步:计算 boston 代币的 tfidf(不带范数)。

公式为:

tf-idf(t, d) = tf(t, d) * idf(t)
idf(t) = log( (n+1) / (df(t)+1) ) + 1
where:
- tf(t,d) -- simple term t frequency in document d
- idf(t) -- smoothed inversed document frequency (because of smooth_idf=True param)

计算第 0 个文档中的标记 boston 及其出现的文档数量:

tfidf_boston_wo_norm = ((1/5) * (np.log((1+5)/(1+2))+1))
tfidf_boston_wo_norm
0.3386294361119891

请注意,根据内置标记化方案,i 不算作标记。

第 3 步:标准化

我们首先进行 l1 标准化,即所有计算出的非标准化 tfdid 的总和应为 1:

l1_norm = ((1/5) * (np.log((1+5)/(1+2))+1) +
(1/5) * (np.log((1+5)/(1+1))+1) +
(1/5) * (np.log((1+5)/(1+2))+1) +
(1/5) * (np.log((1+5)/(1+2))+1) +
(1/5) * (np.log((1+5)/(1+2))+1))
tfidf_boston_w_l1_norm = tfidf_boston_wo_norm/l1_norm
tfidf_boston_w_l1_norm
0.19085884520912985

如您所见,我们得到与上面相同的 tfidf 分数。

现在让我们对 l2 范数进行相同的数学计算。

基准:

tfidf = TfidfVectorizer(sublinear_tf=True,norm='l2')
docs_tfidf = tfidf.fit_transform(docs).todense()
docs_tfidf[:,n]
matrix([[0.42500138],
[0.44400208],
[0. ],
[0. ],
[0. ]])

微积分:

l2_norm = np.sqrt(((1/5) * (np.log((1+5)/(1+2))+1))**2 +
((1/5) * (np.log((1+5)/(1+1))+1))**2 +
((1/5) * (np.log((1+5)/(1+2))+1))**2 +
((1/5) * (np.log((1+5)/(1+2))+1))**2 +
((1/5) * (np.log((1+5)/(1+2))+1))**2
)

tfidf_boston_w_l2_norm = tfidf_boston_wo_norm/l2_norm
tfidf_boston_w_l2_norm
0.42500137513291814

它仍然与人们看到的一样。

关于python - 如何从 SKLearn 的 TfidfVectorizer 手动计算 TF-IDF 分数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60343826/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com