如何在SKLearn的TfidfVectorizer上手动计算TF-IDF输出

问题描述 投票:1回答:1

我一直在运行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表示为令牌的比率='波士顿'(1):所有unigram令牌(4),我都会得到TF为0.25,当我将其应用于TF-IDF时,其得分将刚好超过0.147

[类似地,当我使用令牌比率='波士顿'(1)时:所有NE令牌(2)并应用TF-IDF,我得到的分数为0.846。很明显,我在某处出错。
python scikit-learn tf-idf tfidfvectorizer
1个回答
0
投票
让我们一次一步地完成这个简单的数学练习。

步骤1.获取“波士顿”令牌的tidf分数

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 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得分(vocab中的#3)。

步骤2.为boston代币标准计算tfidf。

公式为:

tf-idf(t,d)= tf(t,d)* idf(t)idf(t)= log((n + 1)/(df(t)+1))+ 1哪里:-tf(t,d)-文档d中的简单术语t频率-idf(t)-平滑反转文档的频率(由于[C​​0]参数)

计算第0个文档中的令牌smooth_idf=True及其在其中显示的文档数量:

boston

注意,根据内置的标记化方案,tfidf_boston_wo_norm = ((1/5) * (np.log((1+5)/(1+2))+1))
tfidf_boston_wo_norm
0.3386294361119891
不算作标记。

步骤3.规范化

让我们首先对i进行标准化,即所有计算出的非标准化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_normtfidf_boston_w_l1_norm0.19085884520912985

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

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

基准:

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. ]])

仍然与可能看到的相同。
© www.soinside.com 2019 - 2024. All rights reserved.