#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