Как рассчитать косинусное сходство с уже рассчитанными показателями TFIDF - PullRequest
0 голосов
/ 16 мая 2018

Мне нужно рассчитать косинусное сходство между документами с уже рассчитанными показателями TFIDF.

Обычно я использовал бы (например) TFIDFVectorizer , который создавал бы матрицу документов / терминов, вычисляя баллы TFIDF по мере необходимости. Я не могу применить это, потому что это пересчитает баллы TFIDF. Это было бы неправильно, потому что документы уже прошли большую предварительную обработку, включая Bag of Words и фильтрацию IDF (я не буду объяснять, почему - слишком долго).

Иллюстративный входной файл CSV:

Doc, Term,    TFIDF score
1,   apples,  0.3
1,   bananas, 0.7
2,   apples,  0.1
2,   pears,   0.9
3,   apples,  0.6
3,   bananas, 0.2
3,   pears,   0.2

Мне нужно сгенерировать матрицу, которая обычно генерируется TFIDFVectorizer, например ::

  | apples | bananas | pears
1 | 0.3    | 0.7     | 0
2 | 0.1    | 0       | 0.9
3 | 0.6    | 0.2     | 0.2 

... чтобы я мог вычислить косинусное сходство между документами.

Я использую Python 2.7, но приветствуются предложения по другим решениям или инструментам. Я не могу легко переключиться на Python 3.

Edit:

Это на самом деле не о транспонировании пустых массивов. Он включает в себя сопоставление баллов TFIDF с матрицей документа / термина с токенами и отсутствующими значениями, заполненными как 0.

Ответы [ 3 ]

0 голосов
/ 17 мая 2018

Предлагаю использовать разреженные матрицы из scipy.sparse

from scipy.sparse import csr_matrix, coo_matrix
from sklearn.metrics.pairwise import cosine_similarity

input="""Doc, Term,    TFIDF score
1,   apples,  0.3
1,   bananas, 0.7
2,   apples,  0.1
2,   pears,   0.9
3,   apples,  0.6
3,   bananas, 0.2
3,   pears,   0.2"""

voc = {}

# sparse matrix representation: the coefficient
# with coordinates (rows[i], cols[i]) contains value data[i]
rows, cols, data = [], [], []

for line in input.split("\n")[1:]: # dismiss header

    doc, term, tfidf = line.replace(" ", "").split(",")

    rows.append(int(doc))

    # map each vocabulary item to an int
    if term not in voc:
        voc[term] = len(voc)

    cols.append(voc[term])
    data.append(float(tfidf))

doc_term_matrix = coo_matrix((data, (rows, cols)))

# compressed sparse row matrix (type of sparse matrix with fast row slicing)
sparse_row_matrix = doc_term_matrix.tocsr()

print("Sparse matrix")
print(sparse_row_matrix.toarray()) # convert to array

# compute similarity between each pair of documents
similarities = cosine_similarity(sparse_row_matrix)

print("Similarity matrix")
print(similarities)

Вывод:

Sparse matrix
[[0.  0.  0. ]
 [0.3 0.7 0. ]
 [0.1 0.  0.9]
 [0.6 0.2 0.2]]
Similarity matrix
[[0.         0.         0.         0.        ]
 [0.         1.         0.04350111 0.63344607]
 [0.         0.04350111 1.         0.39955629]
 [0.         0.63344607 0.39955629 1.        ]]
0 голосов
/ 18 мая 2018

Если вы можете использовать pandas, чтобы сначала прочитать весь файл csv в кадре данных, это станет проще.

import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder

df = pd.read_csv('sample.csv', index_col=None, skipinitialspace=True)

# Converting the text Term to column index
le = LabelEncoder()
df['column']=le.fit_transform(df['Term'])

# Converting the Doc to row index
df['row']=df['Doc'] - 1

# Rows will be equal to max index of document
num_rows = max(df['row'])+1

# Columns will be equal to number of distinct terms
num_cols = len(le.classes_)

# Initialize the array with all zeroes
tfidf_arr = np.zeros((num_rows, num_cols))

# Iterate the dataframe and set the appropriate values in tfidf_arr
for index, row in df.iterrows():
    tfidf_arr[row['row'],row['column']]=row['TFIDF score']

Пройдите через комментарии и спросите, если вы ничего не понимаете.

0 голосов
/ 16 мая 2018

Неэффективный хак, который я оставлю здесь на случай, если он поможет кому-то еще. Другие предложения приветствуются.

def calculate_cosine_distance():
    unique_terms = get_unique_terms_as_list()

    tfidf_matrix = [[0 for i in range(len(unique_terms))] for j in range(TOTAL_NUMBER_OF_BOOKS)]

    with open(INPUT_FILE_PATH, mode='r') as infile:
        reader = csv.reader(infile.read().splitlines(), quoting=csv.QUOTE_NONE)

        # Ignore header row
        next(reader)

        for rows in reader:
            book = int(rows[0]) - 1 # To make it a zero-indexed array
            term_index = int(unique_terms.index(rows[1]))
            tfidf_matrix[book][term_index] = rows[2]

    # Calculate distance between book X and book Y
    print cosine_similarity(tfidf_matrix[0:1], tfidf_matrix)

def get_unique_terms_as_list():
    unique_terms = set()
    with open(INPUT_FILE_PATH, mode='rU') as infile:
        reader = csv.reader(infile.read().splitlines(), quoting=csv.QUOTE_NONE)
        # Skip header
        next(reader)
        for rows in reader:
            unique_terms.add(rows[1])

        unique_terms = list(unique_terms)
    return unique_terms
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...