Я хочу рассчитать tf и idf отдельно из приведенных ниже документов. Я использую python и pandas.
import pandas as pd
df = pd.DataFrame({'docId': [1,2,3],
'sent': ['This is the first sentence','This is the second sentence', 'This is the third sentence']})
Я хочу рассчитать, используя формулу для Tf-Idf, не используя библиотеку Sklearn.
После токенизации я использовал это для расчета TF:
tf = df.sent.apply(pd.value_counts).fillna(0)
но это дает мне счет, но мне нужно соотношение (count/total number of words)
.
Для Idf: df[df['sent'] > 0]/(1 + len(df['sent'])
но, похоже, это не работает. Я хочу, чтобы и Tf, и Idf представляли собой формат серии pandas.
для токенизации я использовал df['sent'] = df['sent'].apply(word_tokenize)
Я получил idf-баллы как:
tfidf = TfidfVectorizer()
feature_array = tfidf.fit_transform(df['sent'])
d=(dict(zip(tfidf.get_feature_names(), tfidf.idf_)))
Как я могу получить оценки tf отдельно?
Вам нужно будет сделать еще немного работы, чтобы вычислить это.
import numpy as np
df = pd.DataFrame({'docId': [1,2,3],
'sent': ['This is the first sentence',
'This is the second sentence',
'This is the third sentence']})
# Tokenize and generate count vectors
word_vec = df.sent.apply(str.split).apply(pd.value_counts).fillna(0)
# Compute term frequencies
tf = word_vec.divide(np.sum(word_vec, axis=1), axis=0)
# Compute inverse document frequencies
idf = np.log10(len(tf) / word_vec[word_vec > 0].count())
# Compute TF-IDF vectors
tfidf = np.multiply(tf, idf.to_frame().T)
print(tfidf)
is the first This sentence second third
0 0.0 0.0 0.095424 0.0 0.0 0.000000 0.000000
1 0.0 0.0 0.000000 0.0 0.0 0.095424 0.000000
2 0.0 0.0 0.000000 0.0 0.0 0.000000 0.095424
В зависимости от вашей ситуации вы можете нормализовать:
# L2 (Euclidean) normalization
l2_norm = np.sum(np.sqrt(tfidf), axis=1)
# Normalized TF-IDF vectors
tfidf_norm = (tfidf.T / l2_norm).T
print(tfidf_norm)
is the first This sentence second third
0 0.0 0.0 0.308908 0.0 0.0 0.000000 0.000000
1 0.0 0.0 0.000000 0.0 0.0 0.308908 0.000000
2 0.0 0.0 0.000000 0.0 0.0 0.000000 0.308908
Вот мое решение:
сначала tokenize, для удобства как отдельный столбец:
df['tokens'] = [x.lower().split() for x in df.sent.values]
затем TF, как вы, но с нормализацией параметра (по техническим причинам вам нужна функция лямбда):
tf = df.tokens.apply(lambda x: pd.Series(x).value_counts(normalize=True)).fillna(0)
затем IDF (по одному на слово в лексике):
idf = pd.Series([np.log10(float(df.shape[0])/len([x for x in df.tokens.values if token in x])) for token in tf.columns])
idf.index = tf.columns
тогда, если вы хотите TFIDF:
tfidf = tf.copy()
for col in tfidf.columns:
tfidf[col] = tfidf[col]*idf[col]
Я думаю, у меня была такая же проблема, как и вы.
Я хотел использовать TfIdfVectorizer, но их определение tf-idf по умолчанию не является стандартным (tf-idf = tf + tf*idf
вместо обычного tf-idf = tf*idf
)
TF = термин "частота" обычно используется для обозначения счета. Для этого вы можете использовать CountVectorizer() из sklearn. Необходимо лог преобразовать и нормализовать, если необходимо.
Опция с использованием numpy была намного больше времени обработки (> 50 раз медленнее).