| import pandas as pd |
| from gensim import corpora |
| from gensim import similarities |
| from gensim.models import TfidfModel |
| from gensim.parsing import strip_tags, strip_numeric, \ |
| strip_multiple_whitespaces, stem_text, strip_punctuation, \ |
| remove_stopwords, preprocess_string |
| import re |
|
|
| from typing import List |
| from utils.constants import TEST_INPUTS |
| import argparse |
| from random import choice |
|
|
| transform_to_lower = lambda s: s.lower() |
| remove_single_char = lambda s: re.sub(r'\s+\w{1}\s+', '', s) |
|
|
| class PaperRecommender: |
| def __init__(self, |
| num_samples=3000, |
| corpus_dictionary_path="30Ktokens", |
| arxiv_dataset_path="/Users/luis.morales/Desktop/arxiv-paper-recommender/data/processed/reduced_arxiv_papers.parquet.gzip", |
| save_dict=False, |
| query=""): |
| self.num_samples = num_samples |
| self.corpus_dictionary_path = corpus_dictionary_path |
| self.arxiv_dataset_path = arxiv_dataset_path |
| self.save_dict = save_dict |
| self.query = query |
| self.cleaning_filters = [ |
| strip_tags, |
| strip_numeric, |
| strip_punctuation, |
| strip_multiple_whitespaces, |
| transform_to_lower, |
| remove_stopwords, |
| remove_single_char |
| ] |
| self.dictionary = None |
| self.index = None |
| self.tfidf_model = None |
| self.df = None |
|
|
| def gensim_tokenizer(self, docs: List[str]): |
| tokenized_docs = list() |
| for doc in docs: |
| processed_words = preprocess_string(doc, self.cleaning_filters) |
| tokenized_docs.append(processed_words) |
| return tokenized_docs |
|
|
| def cleaning_pipe(self, document): |
| processed_words = preprocess_string(document, self.cleaning_filters) |
| return processed_words |
|
|
| def get_gensim_dictionary(self, tokenized_docs: List[str], dict_name: str = "corpus"): |
| dictionary = corpora.Dictionary(tokenized_docs) |
| if self.save_dict: |
| parent_folder = "/Users/luis.morales/Desktop/arxiv-paper-recommender/models/nlp_dictionaries" |
| dictionary.save(f'{parent_folder}/{dict_name}.dict') |
| return dictionary |
|
|
| def get_closest_n(self, query: str, n: int): |
| query_document = self.cleaning_pipe(query) |
| query_bow = self.dictionary.doc2bow(query_document) |
| sims = self.index[self.tfidf_model[query_bow]] |
| top_idx = sims.argsort()[-1 * n:][::-1] |
| return top_idx |
|
|
| def get_recommendations_metadata(self, query: str, n: int): |
| recommendations_idxs = self.get_closest_n(query, n) |
| recommendations_metadata = self.df.iloc[recommendations_idxs] |
| recommendations_metadata = recommendations_metadata.reset_index(drop=True) |
| return recommendations_metadata |
|
|
| def run_recommender(self): |
| if self.num_samples is None: |
| self.df = pd.read_parquet(self.arxiv_dataset_path) |
| |
| self.df = pd.read_parquet(self.arxiv_dataset_path).sample(self.num_samples).reset_index(drop=True) |
| corpus = self.df['cleaned_abstracts'].to_list() |
| |
| tokenized_corpus = self.gensim_tokenizer(corpus) |
| self.dictionary = self.get_gensim_dictionary(tokenized_docs=tokenized_corpus, dict_name=self.corpus_dictionary_path) |
| |
| BoW_corpus = [self.dictionary.doc2bow(doc, allow_update=True) for doc in tokenized_corpus] |
| |
| self.tfidf_model = TfidfModel(BoW_corpus) |
| self.index = similarities.SparseMatrixSimilarity(self.tfidf_model[BoW_corpus], num_features=len(self.dictionary)) |
| if self.query is None: |
| self.query = choice(TEST_INPUTS) |
| return self.results |
|
|