Scikit Learn TfidfVectorizer: как получить лучшие русские термины с самым высоким счетом tf-idf

Я работаю над проблемой извлечения ключевых слов. Рассмотрим очень общий случай

tfidf = TfidfVectorizer(tokenizer=tokenize, stop_words='english')

t = """Two Travellers, walking in the noonday sun, sought the shade of a widespreading tree to rest. As they lay looking up among the pleasant leaves, they saw that it was a Plane Tree.

"How useless is the Plane!" said one of them. "It bears no fruit whatever, and only serves to litter the ground with leaves."

"Ungrateful creatures!" said a voice from the Plane Tree. "You lie here in my cooling shade, and yet you say I am useless! Thus ungratefully, O Jupiter, do men receive their blessings!"

Our best blessings are often the least appreciated."""

tfs = tfidf.fit_transform(t.split(" "))
str = 'tree cat travellers fruit jupiter'
response = tfidf.transform([str])
feature_names = tfidf.get_feature_names()

for col in response.nonzero()[1]:
    print(feature_names[col], ' - ', response[0, col])

и это дает мне

  (0, 28)   0.443509712811
  (0, 27)   0.517461475101
  (0, 8)    0.517461475101
  (0, 6)    0.517461475101
tree  -  0.443509712811
travellers  -  0.517461475101
jupiter  -  0.517461475101
fruit  -  0.517461475101

и это хорошо. Есть ли способ получить первые n терминов с наибольшим счетом tfidf для любого нового документа?

Ответы

Ответ 1

Вы должны сделать немного песни и танца, чтобы получить матрицы как массивные массивы вместо этого, но это должно делать то, что вы ищете:

feature_array = np.array(tfidf.get_feature_names())
tfidf_sorting = np.argsort(response.toarray()).flatten()[::-1]

n = 3
top_n = feature_array[tfidf_sorting][:n]

Это дает мне:

array([u'fruit', u'travellers', u'jupiter'], 
  dtype='<U13')

argsort действительно полезен, вот документы для него. Мы должны сделать [::-1] потому что argsort поддерживает сортировку от малого до большого. Мы называем flatten для уменьшения размеров до 1d, чтобы отсортированные индексы могли использоваться для индексации массива 1d. Обратите внимание, что включение вызова flatten будет работать только в том случае, если вы тестируете один документ во время.

Кроме того, на другой ноте, вы имели в виду что-то вроде tfs = tfidf.fit_transform(t.split("\n\n"))? В противном случае каждый термин в многострочной строке обрабатывается как "документ". Использование \n\n вместо этого означает, что мы на самом деле смотрим на 4 документа (по одному для каждой строки), что имеет больше смысла, когда вы думаете о tfidf.

Ответ 2

Решение с использованием самой разреженной матрицы (без .toarray())!

tfidf = TfidfVectorizer(stop_words='english')
corpus = [
    'I would like to check this document',
    'How about one more document',
    'Aim is to capture the key words from the corpus',
    'frequency of words in a document is called term frequency'
]

X = tfidf.fit_transform(corpus)
feature_names = np.array(tfidf.get_feature_names())


new_doc = ['can key words in this new document be identified?',
           'idf is the inverse document frequency caculcated for each of the words']
responses = tfidf.transform(new_doc)


def get_top_tf_idf_words(response, top_n=2):
    sorted_nzs = np.argsort(response.data)[:-(top_n+1):-1]
    return feature_names[response.indices[sorted_nzs]]

print([get_top_tf_idf_words(response,2) for response in responses])

#[array(['key', 'words'], dtype='<U9'),
 array(['frequency', 'words'], dtype='<U9')]