Как должен работать TFIDFVectorizer в scikit-learn?

Я пытаюсь получить слова, которые отличаются от определенных документов, используя класс TfIDFVectorizer в scikit-learn. Он создает матрицу tfidf со всеми словами и их оценками во всех документах, но затем, похоже, также учитывает общие слова. Это часть кода, который я запускаю:

vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(contents)
feature_names = vectorizer.get_feature_names()
dense = tfidf_matrix.todense()
denselist = dense.tolist()
df = pd.DataFrame(denselist, columns=feature_names, index=characters)
s = pd.Series(df.loc['Adam'])
s[s > 0].sort_values(ascending=False)[:10]

Я ожидал, что это вернет список отличительных слов для документа "Адам", но то, что он делает, возвращает список общих слов:

and     0.497077
to      0.387147
the     0.316648
of      0.298724
in      0.186404
with    0.144583
his     0.140998

Я, возможно, не совсем понимаю это, но, как я понимаю, tf-idf должен найти слова, которые отличаются от одного документа в корпусе, и найти слова, которые часто появляются в одном документе, но не в других документах. Здесь and часто появляется в других документах, поэтому я не знаю, почему он возвращает здесь высокое значение.

Полный код, который я использую для его создания, находится в этом ноутбуке Jupyter.

Когда я вычисляю tf/idfs полу-вручную, используя NLTK и вычислительные оценки для каждого слова, я получаю соответствующие результаты. Для документа "Адам":

fresh        0.000813
prime        0.000813
bone         0.000677
relate       0.000677
blame        0.000677
enough       0.000677

Это выглядит правильно, поскольку это слова, которые появляются в документе "Адам", но не так много в других документах в корпусе. Полный код, используемый для его создания, находится в этом ноутбуке Jupyter.

Я что-то делаю с кодом scikit? Есть ли другой способ инициализировать этот класс, где он возвращает правильные результаты? Конечно, я могу игнорировать стоп-слова, передавая stop_words = 'english', но это на самом деле не решает проблему, поскольку общие слова любого рода не должны иметь высоких оценок здесь.

Ответ 1

Из документации scikit-learn:

Поскольку tf-idf очень часто используется для текстовых функций, есть еще один класс под названием TfidfVectorizer, который объединяет все опции CountVectorizer и TfidfTransformer в одной модели.

Как вы можете видеть, TfidfVectorizer - это CountVectorizer, за которым следует TfidfTransformer.

То, что вы, вероятно, ищете, это TfidfTransformer, а не TfidfVectorizer

Ответ 2

Я считаю, что ваша проблема заключается в использовании разных списков заметок. Scikit-learn и NLTK по умолчанию используют разные списки заметок. Для scikit-learn обычно рекомендуется иметь собственный список stop_words, переданный TfidfVectorizer, например:

my_stopword_list = ['and','to','the','of']
my_vectorizer = TfidfVectorizer(stop_words=my_stopword_list)

Страница Doc для класса TfidfVectorizer: [ http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html][1]

Ответ 3

Я не уверен, почему это не значение по умолчанию, но вы, вероятно, хотите sublinear_tf=True в инициализации для TfidfVectorizer. Я разветкил ваше репо и отправил вам PR с примером, который, вероятно, больше походит на то, что вы хотите.

Ответ 4

используя ниже код, я получаю гораздо лучшие результаты

vectorizer = TfidfVectorizer(sublinear_tf=True, stop_words='english')

Вывод

sustain    0.045090
bone       0.045090
thou       0.044417
thee       0.043673
timely     0.043269
thy        0.042731
prime      0.041628
absence    0.041234
rib        0.041234
feel       0.040259
Name: Adam, dtype: float64

а также

thee          0.071188
thy           0.070549
forbids       0.069358
thou          0.068068
early         0.064642
earliest      0.062229
dreamed       0.062229
firmness      0.062229
glistering    0.062229
sweet         0.060770
Name: Eve, dtype: float64