чтобы построить векторизатор TFIDF с заданным корпусом и сравнить его результаты с помощью Sklearn?

#python #vector #scikit-learn #nlp #tfidfvectorizer

Вопрос:

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

1.Словарь Sklearn, созданный на основе idf, представлен в алфавитном порядке

2.Формула Sklearn idf отличается от стандартной формулы учебника. Здесь константа «1» добавляется к числителю и знаменателю idf, как если бы был виден дополнительный документ, содержащий каждый термин в коллекции ровно один раз, что предотвращает деление на ноль. IDF(t)=1 (loge ((1 Общее количество документов в коллекции)/(1 Количество документов с термином t в нем)).

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(vectorizer.idf_)

OUTPUT:- [1.91629073 1.22314355 1.51082562 1.         1.91629073 1.91629073
 1.         1.91629073 1.        ]

print(skl_output[0])

OUTPUT:-

  (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


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

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)}
    print(list(storage_set))
    return vocab

vocab =  fit(corpus)
print(vocab)

OUPUT:- ['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']
{'and': 0, 'document': 1, 'first': 2, 'is': 3, 'one': 4, 'second': 5, 'the': 6, 'third': 7, 'this': 8}

def idf(dataset,word):
    c=0
    for i in dataset:
        if word in i.split():
            c=c 1
    return c

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(dataset,word)))
                values.append((td) * (idf_))
    print(values)            
    return normalize(csr_matrix( ((values),(row,col)), shape=(len(dataset),len(vocab))),norm='l2' )


p=transform(corpus,vocab)
print(p[0])

with this i'm getting ouput:
 

[0.038461538461538464, 0.038461538461538464, 0.038461538461538464, 0.05810867783715349, 0.04704398274285422, 0.027777777777777776, 0.06795241951745609, 0.027777777777777776, 0.027777777777777776, 0.05323029810761542, 0.0766516292749662, 0.04, 0.04, 0.04, 0.0766516292749662, 0.0766516292749662, 0.038461538461538464, 0.038461538461538464, 0.038461538461538464, 0.05810867783715349, 0.04704398274285422]

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

so clearly the value of (vectorizer.idf_) amp; skl_output[0] is not matching with mine .

is something wrong with my idf() function? ANy insight will be helpful