#python #text #tf-idf
#python #текст #tf-idf
Вопрос:
Моя цель — сравнить текст txt с каждым элементом в корпусе ниже, используя схему взвешивания TFIDF.
корпус=[‘школьник читает’, ‘кто читает комикс?’, ‘маленький мальчик читает’]
txt=’Школьник Джеймс всегда занят чтением’
Вот моя реализация:
TFIDF = частота терминов -обратная частота документов = tf * log (n / df) n = количество документов в корпусе — в данном случае 3
import collections
from collections import Counter
from math import log
txt2=Counter(txt.split())
corpus2=[Counter(x.split()) for x in corpus]
def tfidf(doc,_corpus):
dic=collections.defaultdict(int)
for x in _corpus:
for y in x:
dic[y] =1
for x in doc:
if x not in dic:dic[x]=1.
return {x : doc[x] * log(3.0/dic[x])for x in doc}
txt_tfidf=tfidf(txt2, corpus2)
corpus_tfidf=[tfidf(x, corpus2) for x in corpus2]
Результаты
print txt_tfidf
{'boy': 0.4054651081081644, 'school': 1.0986122886681098, 'busy': 1.0986122886681098, 'James': 1.0986122886681098,
'is': 0.0, 'always': 1.0986122886681098, 'the': 0.4054651081081644, 'reading': 0.0}
for x in corpus_tfidf:
print x
{'boy': 0.4054651081081644, 'the': 0.4054651081081644, 'reading': 0.0, 'school': 1.0986122886681098, 'is': 0.0}
{'a': 1.0986122886681098, 'is': 0.0, 'who': 1.0986122886681098, 'comic?': 1.0986122886681098, 'reading': 0.0}
{'boy': 0.4054651081081644, 'the': 0.4054651081081644, 'reading': 0.0, 'little': 1.0986122886681098, 'is': 0.0}
Я не совсем уверен, прав ли я, потому что редкие термины, такие как Джеймс и комикс, должны иметь более высокие веса TFIDF, чем обычный термин, такой как школа.
Любые предложения будут оценены.
Комментарии:
1. Хотя ‘school’, возможно, более распространено в английском языке, ‘school’ имеет то же распределение, что и ‘comic?’ в вашем наборе данных, поэтому, похоже, их оценки должны быть одинаковыми
2. @confuser, но school появляется дважды, а comic появляется один раз, или это просто о корпусе? И, пожалуйста, дайте мне знать, верна ли моя реализация, и любые предложения о том, как провести сравнение. Спасибо.
3. А, понятно. Я считаю , что все предложения (включая
txt
) должны быть частью корпуса, чтобы TF-IDF действительно имел смысл. (Может быть, кто-то более осведомленный в этом может подтвердить это?)
Ответ №1:
Прежде всего, как сказал @confuser в комментариях, давайте поместим txt в корпус и избавимся от этого кода:
for x in doc:
if x not in dic:dic[x]=1.
После этого я хочу добавить a .
в ваш код, потому что точка в кодировании — это как соль в кулинарии. 😉
for y in x:
dic[y] = 1.
О, я также вижу некоторые магические числа в вашем коде. Извините, но они заставляют меня нервничать, поэтому у нас есть:
return {x: doc[x] * log(len(_corpus) / dic[x]) for x in doc}
Со всеми этими небольшими изменениями мы можем видеть результат кода ниже:
import collections
from collections import Counter
from math import log
corpus = ['the school boy is reading', 'who is reading a comic?', 'the little boy is reading',
'James the school boy is always busy reading']
txt = corpus[-1]
txt2 = Counter(txt.split())
corpus2 = [Counter(x.split()) for x in corpus]
def tfidf(doc, _corpus):
dic = collections.defaultdict(int)
for x in _corpus:
for y in x:
dic[y] = 1.
return {x: doc[x] * log(len(_corpus) / dic[x]) for x in doc}
txt_tfidf = tfidf(txt2, corpus2)
corpus_tfidf = [tfidf(x, corpus2) for x in corpus2]
print txt_tfidf
Мне кажется нормальным 'boy'
иметь гораздо меньше tf_idf, чем 'busy'
. Вы согласны?
{'boy': 0.28768207245178085, 'school': 0.6931471805599453, 'busy': 1.3862943611198906, 'James': 1.3862943611198906, 'is': 0.0, 'always': 1.3862943611198906, 'the': 0.28768207245178085, 'reading': 0.0}
Комментарии:
1. большое спасибо за ваш вклад, ваш ответ и объяснение просто идеальны. Я получил точно такой же ответ около часа назад.