Как построить TFIDF Vectorizer с учетом корпуса и сравнить его результаты с помощью Sklearn? - PullRequest
1 голос
/ 03 февраля 2020

Sklearn делает несколько изменений в реализации своей версии векторизатора TFIDF, поэтому, чтобы воспроизвести точные результаты, вам нужно добавить следующие вещи в свою пользовательскую реализацию векторизатора tfidf:

  1. У Sklearn есть свои словарь, сгенерированный из idf sroted в алфавитном порядке
  2. Sklearn формула idf отличается от стандартной формулы учебника. Здесь константа «1» добавляется в числитель и знаменатель idf, как если бы был замечен дополнительный документ, содержащий каждый термин в коллекции ровно один раз, что предотвращает деление на ноль. IDF(t)=1+(loge((1 + Total number of documents in collection)/(1+Number of documents with term t in it)).
  3. Sklearn применяет Нормализация L2 к своей выходной матрице.
  4. Окончательный вывод векторизатора sklearn tfidf является разреженной матрицей.

Сейчас с учетом следующего корпуса:

corpus = [
     'this is the first document',
     'this document is the second document',
     'and this is the third one',
     'is this the first document',
]

Реализация Sklearn:

from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer()
vectorizer.fit(corpus)
skl_output = vectorizer.transform(corpus)
print(vectorizer.get_feature_names())
output : [‘and’, ‘document’, ‘first’, ‘is’, ‘one’, ‘second’, ‘the’, ‘third’, ‘this’]

print(skl_output[0])

Вывод:

(0, 8)    0.38408524091481483
(0, 6)    0.38408524091481483
(0, 3)    0.38408524091481483
(0, 2)    0.5802858236844359
(0, 1)    0.46979138557992045

Мне нужно повторить приведенный выше результат с помощью пользовательской реализации, т.е. записи простой код python.

Я написал следующий код:

from collections import Counter
from tqdm import tqdm
from scipy.sparse import csr_matrix
import math
import operator
from sklearn.preprocessing import normalize
import numpy
​

# The fit function helps in creating a vocabulary of all the unique words in the corpus
​

def fit(dataset):
  storage_set = set()
  if isinstance(dataset,list):
    for document in dataset:
      for word in document.split(" "):
        storage_set.add(word)
  storage_set = sorted(list(storage_set))
  vocab = {j:i for i,j in enumerate(storage_set)}
  return vocab

vocab =  fit(corpus)
print(vocab)
output : {‘and’: 0, ‘document’: 1, ‘first’: 2, ‘is’: 3, ‘one’: 4, ‘second’: 5, ‘the’: 6, ‘third’: 7, ‘this’: 8}
This output is matching with the output of the sklearn above
#Returs a sparse matrix of the all non-zero values along with their row and col 
def transform(dataset,vocab):
  row = []
  col = []
  values = []
  for ibx,document in enumerate(dataset):
    word_freq = dict(Counter(document.split()))
    for word, freq in word_freq.items():
      col_index = vocab.get(word,-1)
      if col_index != -1:
        if len(word)<2:
          continue
        col.append(col_index)
        row.append(ibx)
        td = freq/float(len(document)) # the number of times a word occured in a document
        idf_ = 1+math.log((1+len(dataset))/float(1+idf(word)))
        values.append((td) * (idf_))
    return normalize(csr_matrix( ((values),(row,col)), shape=(len(dataset),len(vocab))),norm='l2' )

print(transform(corpus,vocab))

Вывод:

(0, 1)    0.3989610517704845
(0, 2)    0.602760579899478
(0, 3)    0.3989610517704845
(0, 6)    0.3989610517704845
(0, 8)    0.3989610517704845

Как видите, этот вывод не совпадает с значения из вывода sklearn. Я несколько раз пролистал логи c, везде пробовал отлаживать. Тем не менее, я не смог определить, почему моя пользовательская реализация не соответствует выводу sklearn. Буду признателен за любые идеи.

...