Рекомендательная система для вашего каталога научных работ (и не только!). machinelearning.. machinelearning. ml.. machinelearning. ml. nlp.. machinelearning. ml. nlp. python.. machinelearning. ml. nlp. python. обработка естественного языка.. machinelearning. ml. nlp. python. обработка естественного языка. рекомендательная система.. machinelearning. ml. nlp. python. обработка естественного языка. рекомендательная система. теория графов.

Используем обработку естественного языка и теорию графов для сравнения и рекомендации различных типов документов.

Введение

Почти все проекты начинаются с одного важного этапа — активных исследований. Инвестировать в то, что уже было сделано другими, в развитие их работы — это один из путей к повышению ценности вашего проекта. Важно не только извлечь уроки из опыта других, но и понять, чего не стоит делать в своем проекте, чтобы повысить его шансы на успех.

В процессе работы над своей диссертацией я собрал множество различных исследовательских материалов. Среди них были подборки научных публикаций, которые я прочитал, и Excel‑таблицы с результатами экспериментов. Завершая исследование для своей диссертации, я задался вопросом: а есть ли способ создать систему рекомендаций, которая могла бы сравнить все исследования, имеющиеся в моем архиве, и помочь мне в моих следующих проектах?

На самом деле решение есть!

Примечание: Эта идея применима не только к хранилищу научных материалов, которые вы накопили в рамках своих исследований, но и к любому другому каталогу, содержащему различные типы документов.

Сетап

Я разработал эту рекомендательную систему вместе со своей командой, используя Python 3. Спасибо им за помощь! Мы создали что‑то поистине удивительное!

Эта рекомендательная система задействует целый ряд разных API, изучение возможностей которых может быть очень полезным для вашего профессионального развития.

import string 
import csv
from io import StringIO
from pptx import Presentation
import docx2txt
import PyPDF2
import spacy
import pandas as pd 
import numpy as np
import nltk 
import re
import openpyxl
from nltk.stem import WordNetLemmatizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from gensim.parsing.preprocessing import STOPWORDS as SW
nltk.download('stopwords')
nltk.download('wordnet')
nltk.download('omw-1.4')
nltk.download('averaged_perceptron_tagger')
from nltk.corpus import wordnet
import networkx as nx
from networkx.algorithms.shortest_paths import weighted
import glob

Препятствия

Одним из самых сложных препятствий, с которым я столкнулся, было требование, чтобы рекомендательная система могла сравнивать файлы разных типов. Например, я хотел проверить, содержит ли электронная таблица Excel похожую или связанную информацию с данными из PowerPoint и научного журнала в формате PDF. Чтобы решить эту задачу, я считывал каждый тип файла на Python и преобразовывал каждый объект в строку, состоящую из слов. Это позволило мне нормализовать все данные и вычислить показатель сходства.

Класс для чтения PDF

Первым классом, который мы рассмотрим в рамках данного проекта, является класс PdfReader. Этот класс предназначен для преобразования PDF‑файлов в формат, который можно легко читать на языке Python. Среди всех форматов файлов я бы отметил, что PDF‑файлы являются одними из самых важных, поскольку многие журнальные статьи, загружаемые из исследовательских репозиториев, таких как Google Scholar, представлены именно в этом формате.

class pdfReader:

    def __init__(self, file_path: str) -> str:
        self.file_path = file_path

    def PDF_one_pager(self) -> str:
        """Функция, которая возвращает однострочное представление 
            pdf.

            Возвращает:
            one_page_pdf (str): строка, содержащая весь текст pdf-файла.

        """
        content = ""
        p = open(self.file_path, "rb")
        pdf = PyPDF2.PdfReader(p)
        num_pages = len(pdf.pages)
        for i in range(0, num_pages):
            content += pdf.pages[i].extract_text() + "n"
        content = " ".join(content.replace(u"xa0", " ").strip().split())
        page_number_removal = r"d{1,3} of d{1,3}"
        page_number_removal_pattern = re.compile(page_number_removal, re.IGNORECASE)
        content = re.sub(page_number_removal_pattern, '',content)

        return content

    def pdf_reader(self) -> str:
        """Функция, которая может читать файлы в формате .pdf 
            и возвращает PDF-файл, читаемый на python.

            Возвращает:
            read_pdf: A python readable .pdf file.
        """
        opener = open(self.file_path,'rb')
        read_pdf = PyPDF2.PdfFileReader(opener)

        return read_pdf

    def pdf_info(self) -> dict:
        """ Функция, которая возвращает информационный
        словарь PDF. 

        Возвращает:
        dict(pdf_info_dict): словарь, содержащий метаданные
        объекта.
        """
        opener = open(self.file_path,'rb')
        read_pdf = PyPDF2.PdfFileReader(opener)
        pdf_info_dict = {}
        for key,value in read_pdf.documentInfo.items():
            pdf_info_dict[re.sub('/',"",key)] = value
        return pdf_info_dict

    def pdf_dictionary(self) -> dict:
        """Функция, которая возвращает слова, в котором 
            ключами являются страницы,а текст на страницах - это значения.

            Возвращает:
            dict(pdf_dict): страницы и текст словаря.
        """
        opener = open(self.file_path,'rb')

        read_pdf = PyPDF2.PdfReader(opener)
        length = read_pdf.pages
        pdf_dict = {}
        for i in range(length):
            page = read_pdf.getPage(i)
            text = page.extract_text()
            pdf_dict[i] = text
            return pdf_dict

Класс для чтения Microsoft Powerpoint

Класс pptReader предназначен для чтения файлов Microsoft Powerpoint в Python.

class pptReader:

    def __init__(self, file_path: str) -> None:
        self.file_path = file_path

    def ppt_text(self) -> str:
    """Функция, которая возвращает строку текста из всех 
       слайдов объекта pptReader.

      Возвращает:
      text (str): строка, содержащая текст 
      каждого слайда объекта pptReader.
   """
      prs = Presentation(self.file_path)
      text = str()

      for slide in prs.slides:
        for shape in slide.shapes:
          if not shape.has_text_frame:
              continue
          for paragraph in shape.text_frame.paragraphs:
            for run in paragraph.runs:
              text += ' ' + run.text
      return text

Класс для чтения документов Microsoft Word

Класс wordDocReader позволяет читать документы Microsoft Word в Python с помощью API doc2txt. Он возвращает строку с текстом/информацией, содержащейся в данном Word‑документе.

class wordDocReader:
  def __init__(self, file_path: str) -> str:
    self.file_path = file_path

  def word_reader(self):
  """Функция, преобразующая объект wordDocReader в формат,
     читаемый в Python word-документ."""

    text = docx2txt.process(self.file_path)
    text = text.replace('n', ' ')
    text = text.replace('xa0', ' ')
    text = text.replace('t', ' ')
    return text 

Класс для чтения Microsoft Excel

Некоторые авторы включают в свои публикации таблицы с результатами в формате Excel. Возможность прочитать названия столбцов и даже сами значения может помочь рекомендовать результаты, похожие на те, которые вы ищете. Например, если вы изучаете информацию о старых котировках конкретной акции, то, возможно, вам понадобятся название и символ, указанные в таблице Excel с историческими данными. Наша система рекомендаций предложит вам эту таблицу, что значительно упростит вам процесс исследования.

class xlsxReader:

    def __init__(self, file_path: str) -> str:
        self.file_path = file_path

    def xlsx_text(self):
      """Функция, которая возвращает строковое представление 
         Excel-документ.

          Возвращает:
          text(str): строка с текста документа.
      """
      inputExcelFile = self.file_path
      text = str()
      wb = openpyxl.load_workbook(inputExcelFile)
      #Сохраняет excel-страницу в виде CSV-файла
      for sn in wb.sheetnames:
        excelFile = pd.read_excel(inputExcelFile, engine = 'openpyxl', sheet_name = sn)
        excelFile.to_csv("ResultCsvFile.csv", index = None, header=True)

        with open("ResultCsvFile.csv", "r") as csvFile: 
          lines = csvFile.read().split(",") # "rn" если нужно
          for val in lines:
            if val != '':
              text += val + ' '
          text = text.replace('ufeff', '')
          text = text.replace('n', ' ')
      return textCSV File Reader

Класс CSVReader позволит вам включать CSV‑файлы в вашу базу данных, чтобы задействовать их в рекомендациях системы.

class csvReader:

    def __init__(self, file_path: str) -> str:
        self.file_path = file_path

    def csv_text(self):
      """Функция, которая возвращает строку
         csv-документа.

          Возвращает:
          text(str): строка с текстом csv-документа.
      """
      text = str()
      with open(self.file_path, "r") as csvFile: 
        lines = csvFile.read().split(",") # "rn" if needed
        for val in lines:
          text += val + ' '
        text = text.replace('ufeff', '')
        text = text.replace('n', ' ')
      return textMicrosoft PowerPoint Reader

Еще один важный момент — не многие задумываются о том, сколько ценной информации содержится в текстах презентаций PowerPoint. Эти презентации предназначены для того, чтобы донести до аудитории ключевые идеи и важные сведения. В следующем разделе мы научимся связывать любые презентации PowerPoint, которые есть в вашей базе данных, с другими источниками информации. Это поможет вам создавать более целостные и взаимосвязанные рабочие элементы.

class pptReader:

    def __init__(self, file_path: str) -> str:
        self.file_path = file_path

    def ppt_text(self):
      """Функция, которая возвращает строковое представление 
        документа Microsoft PowerPoint.

        Возвращает:
        text(str): строка с текстом документа.
    """
      prs = Presentation(self.file_path)
      text = str()
      for slide in prs.slides:
        for shape in slide.shapes:
          if not shape.has_text_frame:
              continue
          for paragraph in shape.text_frame.paragraphs:
            for run in paragraph.runs:
              text += ' ' + run.text

      return textMicrosoft Word Document Reader

Последним классом в этой системе является программа для чтения документов Microsoft Word. Word‑документы представляют собой еще один важный источник информации. Многие люди пишут отчеты, в которых излагают свои выводы и идеи в формате Word‑документа.

class wordDocReader:
  def __init__(self, file_path: str) -> str:
    self.file_path = file_path

  def word_reader(self):
    """Функция, которая возвращает строковое представление 
       документа Microsoft Word.

          Возвращает:
          text(str): строка с текстом документа.
      """
    text = docx2txt.process(self.file_path)
    text = text.replace('n', ' ')
    text = text.replace('xa0', ' ')
    text = text.replace('t', ' ')
    return text 

В нашем сегодняшнем проекте мы ограничимся этими классами. Обратите внимание, что есть много других типов файлов, которые вы можете задействовать для улучшения вашей рекомендательной системы. Например, в версии кода, над которой мы работаем в данный момент, мы будем принимать изображения и пытаться сопоставить их с другими документами в базе данных.


Обработка данных

Предварительная обработка

В этом разделе мы подробно рассмотрим процесс предварительной обработки данных для нашей рекомендательной системы. Данная система была разработана для хранилища научных работ, поэтому особенно важно было разделить текст на части с помощью ряда этапов предварительной обработки с задействованием NLP.

Класс обработки данных называется просто datapreprocessor. Первая функция в этом классе — средство распознавания частей речи.

class dataprocessor:
  def __init__(self):
    return

  @staticmethod
  def get_wordnet_pos(text: str) -> str:
    """Сопоставьте POS-тег с первым символом, который
    принимает функция lemmatize()
    Inputs:
    text(str): строка текста

    Возвращает:
    tag_dict(dict): словарь тегов
    """
    tag = nltk.pos_tag([text])[0][1][0].upper()
    tag_dict = {"J": wordnet.ADJ,
                "N": wordnet.NOUN,
                "V": wordnet.VERB,
                "R": wordnet.ADV}

    return tag_dict.get(tag, wordnet.NOUN)

Эта функция помечает части речи каждого слова, что будет полезно для дальнейшего использования в проекте.

Далее следует функция, которая выполняет стандартные шаги NLP, уже хорошо знакомые многим из нас. Эти шаги включают:

  1. Перевод каждого слова в нижний регистр.

  2. Удаление знаков препинания.

  3. Удаление цифр (меня не интересовала числовая информация, но вы при желании можете пропустить этот шаг).

  4. Удаление стоп‑слов.

  5. Лемматизация. Вот где нам пригодится функция get_wordnet_pos() для включения частей речи!

@staticmethod
  def preprocess(text: str):
    """Функция, которая выполняет этапы предварительной
    обработкой текста (NLP).
      Inputs:
      text(str): строка текста

      Возвращает:
      text(str): обработанная строка текста
      """
    #нижний регистр
    text = text.lower()

    #удаление знаков препинания
    text = "".join([i for i in text if i not in string.punctuation])

    #удаление цифр(только для полностью числовых значений)
    text = [x for x in text.split(' ') if x.isnumeric() == False]

    #удаление стоп-слов
    stopwords = nltk.corpus.stopwords.words('english')
    custom_stopwords = ['n','nn', '&', ' ', '.', '-', '$', '@']
    stopwords.extend(custom_stopwords)

    text = [i for i in text if i not in stopwords]
    text = ' '.join(word for word in text)

    #лемматизация
    lm = WordNetLemmatizer()
    text = [lm.lemmatize(word, dataprocessor.get_wordnet_pos(word)) for word in text.split(' ')]
    text = ' '.join(word for word in text)

    text = re.sub(' +', ' ',text)

    return text

И наконец, функция для чтения всех файлов в системе:

@staticmethod
  def data_reader(list_file_names):
    """Функция, которая считывает данные из каталога файлов.

    Входные данные:
    list_file_names(list): список путей к файлам в каталоге.

    Возвращает:
     text_list (list): список, в котором каждое значение представляет
    собой текстовую строку для каждого файла в каталоге
     file_dict(dict): словарь, ключами которого являются имя файла,
    а значения — информация в соответствующем файле
    """

    text_list = []
    reader = dataprocessor()
    for file in list_file_names:
      temp = file.split('.')
      filetype = temp[-1]
      if filetype == "pdf":
        file_pdf = pdfReader(file)
        text = file_pdf.PDF_one_pager()

      elif filetype == "docx":
        word_doc_reader = wordDocReader(file)
        text = word_doc_reader.word_reader()

      elif filetype == "pptx" or filetype == 'ppt':
        ppt_reader = pptReader(file)
        text = ppt_reader.ppt_text()

      elif filetype == "csv":
        csv_reader = csvReader(file)
        text = csv_reader.csv_text()

      elif filetype == 'xlsx':
        xl_reader = xlsxReader(file)
        text = xl_reader.xlsx_text()
      else:
        print('File type {} not supported!'.format(filetype))
        continue

      text = reader.preprocess(text)
      text_list.append(text)
      file_dict = dict()
      for i,file in enumerate(list_file_names):
        file_dict[i] = (file, file.split('/')[-1])
    return text_list, file_dict

Поскольку это лишь первая версия данной системы, я хочу подчеркнуть, что код может быть легко адаптирован для обработки множества других типов файлов!

Следующая функция под именем database_preprocess() предназначена для обработки всех файлов в вашей базе данных. Входные данные представляют собой список файлов, каждый из которых содержит уже обработанную текстовую строку. Затем эти строки с текстом подвергаются векторизации с помощью tfidVectorizer из пакета sklearn. Что конкретно он делает? В сущности, tfidVectorizer преобразует весь текст в различные векторы признаков, основываясь на частоте каждого отдельного слова. Это позволяет нам оценить степень связанности документов, используя формулы подобия из векторной арифметики.

@staticmethod
@staticmethod
  def database_processor(file_dict,text_list: list):
    """Функция, преобразующая текст каждого файла в пределах 
    базы данных в вектор.

    Входные данные:
     file_dict(dict): словарь, ключами которого являются имя
    файла, а значения — информация в соответствующем файле
    text_list (list): список, в котором каждое значение представляет
    собой текстовую строку для каждого файла в каталоге

    Возвращает:
     list_dense(list): список текстовых файлов, преобразованных в векторы.
    vectorizer: векторизатор, используемый для преобразования
    строкового представления текста
    file_vector_dict(dict): словарь, в котором ключами
    являются имена файлов, значения —
    векторными представлениями текста соответствующих файлов.
    """
    file_vector_dict = dict()
    vectorizer = TfidfVectorizer()
    vectors = vectorizer.fit_transform(text_list)
    feature_names = vectorizer.get_feature_names_out()
    matrix = vectors.todense()
    list_dense = matrix.tolist()
    for i in range(len(list_dense)):
      file_vector_dict[file_dict[i][1]] = list_dense[i]

    return list_dense, vectorizer, file_vector_dict

Главная причина, по которой векторизатор разрабатывается отдельно от базы данных, заключается в том, что когда пользователь вводит список терминов для поиска в базе данных, эти слова преобразуются в векторы на основе их частоты в указанной базе. Это является самым слабым местом текущей системы. По мере роста объема базы данных время и вычислительные ресурсы, необходимые для определения подобий, будут увеличиваться, что замедлит работу системы. Одна из рекомендаций, которая была предложена на совещании по контролю качества, заключалась в использовании обучения с подкреплением для предоставления рекомендаций по различным категориям данных.

Затем мы можем задействовать обработчик ввода, который будет обрабатывать каждое слово, предоставленное в виде вектора. Это напоминает процесс ввода запроса в поисковую систему:

@staticmethod
  def input_processor(text, TDIF_vectorizor):
    """Функция, которая принимает строку текста и
     векторизирует текст с помощью TDIF-векторизатора.

    Входные данные:
    text(str): строка текста
    TDIF_vectorizor: Предварительно обученный векторизатор

    Возвращает:
    words(list): список входного текста в векторной форме.
    """
    words = ''
    total_words = len(text.split(' '))
    for word in text.split(' '):
      words += (word + ' ') * total_words
      total_words -= 1

    words = [words[:-1]]
    words = TDIF_vectorizor.transform(words)
    words = words.todense()
    words = words.tolist()
    return words

Так как вся информация в базе данных и при ее передаче будет представлена в виде векторов, мы можем использовать косинусный коэффициент для расчета угла между векторами. Чем ближе угол к нулю, тем менее схожими будут два указанных вектора.

@staticmethod
  def similarity_checker(vector_1, vector_2):
    """Функция, которая принимает два вектора и вычисляет их 
    косинусный коэффициент.

    Входные данные:
    vector_1(int): числовой вектор
    vector_2(int): числовой вектор

    Возвращает:
    cosine_similarity([vector_1], vector_2) (int): оценка косинусного коэффициента
    """
    vectors = [vector_1, vector_2]
    for vec in vectors:
      if np.ndim(vec) == 1:
        vec = np.expand_dims(vec, axis=0)
    return cosine_similarity([vector_1], vector_2)

Как только мы сможем определять степень сходства между двумя векторами, у нас появится возможность составлять оценки для заданных слов и документов, хранящихся в базе данных.

@staticmethod
  def recommender(vector_file_list,query_vector, file_dict):
    """Функция, которая принимает список векторов, векторы
    запросов и словарь для списка векторов с их исходными
    значениями и именами файлов.

    Входные данные:
    vector_file_list(list): список векторов
    query_vector(int): числовой вектор
    file_dict(dict): словарь имен файлов и текстом для списка
    векторов

    Возвращает:
    final_recommendation (list): список рекомендуемых файлов
    similarity_list[:len(final_recommendation)] (list): список оценок 
    сходства предлагаемых рекомендаций.
    """
    similarity_list = []
    score_dict = dict()
    for i,file_vector in enumerate(vector_file_list):
      x = dataprocessor.similarity_checker(file_vector, query_vector)
      score_dict[file_dict[i][1]] = (x[0][0])
      similarity_list.append(x)
    similarity_list = sorted(similarity_list, reverse = True)
    #Рекомендует лучшие 20%
    recommended = sorted(score_dict.items(), 
                  key=lambda x:-x[1])[:int(np.round(.5*len(similarity_list)))]

    final_recommendation = []
    for i in range(len(recommended)):
      final_recommendation.append(recommended[i][0])
    #добавляем в граф, если рекомендаций более 3
    return final_recommendation, similarity_list[:len(final_recommendation)]

Список векторных файлов представляет собой перечень векторов, которые мы ранее извлекли из различных файлов. Вектор запроса содержит слова, которые пользователь ищет. Ранее мы создали файловый словарь, в котором имена файлов используются в качестве ключей, а текст файлов — в качестве значений. Для вычисления сходств между векторами мы используем мощный алгоритм косинусного подобия. Затем мы создаем рейтинг, в котором выбираем наиболее похожие фрагменты информации по отношению к запрашиваемым словам. Эти фрагменты предлагаются пользователю в первую очередь. Однако, что делать, если количество рекомендаций превышает три? Включение элементов теории графов и сетей в нашу систему позволит повысить вычислительную эффективность и создать более надежные рекомендации.


Алгоритм PageRank

Давайте сделаем небольшое отступление и поговорим о теории, которая касается алгоритма PageRank. Не поймите меня неправильно, косинусный коэффициент — это эффективный метод для измерения сходства между векторами. Но включение PageRank в алгоритм рекомендаций позволяет сравнивать сходство по нескольким векторам (данным в нашей базе данных).

PageRank был впервые предложен Ларри Пейджем для ранжирования веб‑сайтов и оценки их значимости. Его основная идея заключалась в том, что веб‑сайт считается «более важным», если на него ссылается большее количество других сайтов. Согласно этой концепции, узел на графе может быть оценен как более важный, если расстояние от его ребра до других узлов меньше. Чем короче общее расстояние между узлом и остальными узлами в графике, тем выше его значимость.

Сегодня мы познакомимся с одним из вариантов алгоритма PageRank, который называется «центральность по собственному значению/вектору» (eigenvector centrality). Этот алгоритм, как и PageRank, оценивает связи между узлами на графике, присваивая более высокие баллы тем, у кого эти связи сильнее. Однако есть одно существенное отличие: степень центральности учитывает важность узлов, которые связаны с данным узлом, чтобы оценить его собственную значимость. Это можно сравнить с утверждением о том, что человек, который знаком со многими важными людьми, может стать очень важным сам благодаря этим крепким связям. В целом, эти два алгоритма очень похожи по своей реализации.


После вычисления векторов для этой базы данных, они могут быть представлены в виде графы, где расстояние между его вершинами определяется их сходством с другими векторами.

@staticmethod
  def ranker(recommendation_val, file_vec_dict):
    """Функция, которая принимает список рекомендуемых
    значений и файлы словарей с базой данных и их векторами.

    Входные данные:
    reccomendation_val(list): список рекомендаций, найденных
    с помощью косинусного коэффициента
    file_vec_dic(dict): словарь, где в качестве ключей 
    выступают имена файлов, а в качестве значений — векторное 
    представление текста.

    Возвращает:
    ec_recommended(list): список из 20% лучших рекомендаций,
    найденных с помощью алгоритма центральности по 
    собственному вектору.
    """
    my_graph = nx.Graph()
    for i in range(len(recommendation_val)):
      file_1 = recommendation_val[i]
      for j in range(len(recommendation_val)):
        file_2 = recommendation_val[j]

        if i != j:
          #Вычисляем sim_score между двумя значениями (вес)
          edge_dist = cosine_similarity([file_vec_dict[recommendation_val[i]]],[file_vec_dict[recommendation_val[j]]])
          #add an edge from file 1 to file 2 with the weight 
          my_graph.add_edge(file_1, file_2, weight=edge_dist)

    #Pagerank графа     
    rec = nx.eigenvector_centrality(my_graph)
    #Принимает 20% значений
    ec_recommended = sorted(rec.items(), key=lambda x:-x[1])[:int(np.round(len(rec)))]

    return ec_recommended

Итак, что же теперь? У нас есть рекомендации, полученные на основе косинусного коэффициента между каждой точкой данных в нашей базе, и рекомендации, рассчитанные с использованием алгоритма центральности. Какие из этих рекомендаций мы должны использовать? Обе!

@staticmethod
  def weighted_final_rank(sim_list,ec_recommended,final_recommendation):
    """Функция, которая принимает список значений сходства, 
      найденных с помощью косинусного коэффициента, рекомендации, 
      найденные по степени центральности, и окончательные рекомендации, 
      полученные с помощью косинусного коэффициента.


        Входные данные:
        sim_list(list): список всех значений сходства для файлов
        в базе данных.
        ec_recommended(list): список из 20% лучших рекомендаций, 
        определенных на основе степени центральности.
        final_recommendation (list): список окончательных рекомендаций,
        определенных с помощью косинусного коэффициента.

        Возвращает:
        weighted_final_recommend(list): Список окончательных
        рекомендаций файлов в базе данных.
        """
    final_dict = dict()

    for i in range(len(sim_list)):
      val = (.8*sim_list[final_recommendation.index(ec_recommendation[i][0])].squeeze()) + (.2 * ec_recommendation[i][1])
      final_dict[ec_recommendation[i][0]] = val

    weighted_final_recommend = sorted(final_dict.items(), key=lambda x:-x[1])[:int(np.round(len(final_dict)))]

    return weighted_final_recommend

Финальная функция этого скрипта будет взвешивать различные рекомендации, полученные с учетом косинусного коэффициента и степени центральности. В настоящее время 80% веса уделяется рекомендациям, полученным с помощью косинусного коэффициента, и 20% — рекомендациям, основанным на алгоритме центральности. На основе этих весов мы можем рассчитать окончательные рекомендации и объединить их, чтобы получить более репрезентативный результат для всех вычислений подобия в системе. Разработчики могут легко изменять веса в зависимости от того, какой тип рекомендаций они считают более важным.

Пример

Позвольте продемонстрировать вам небольшой пример использования этого кода. Все документы в моей базе данных представлены в описанных выше форматах и относятся к различным областям машинного обучения. Однако больше всего в ней документов, связанных с генеративными‑состязательными сетями (GAN), поэтому я предполагаю, что они должны быть рекомендованы в первую очередь, когда в качестве поискового термина используется «Generative adversarial network».

path = '/content/drive/MyDrive/database/'
db = [f for f in glob.glob(path + '*')]

research_documents, file_dictionary = dataprocessor.data_reader(db)
list_files, vectorizer, file_vec_dict = dataprocessor.database_processor(file_dictionary,research_documents)
query = 'Generative Adversarial Networks'
query = dataprocessor.preprocess(query)
query = dataprocessor.input_processor(query, vectorizer)
recommendation, sim_list = dataprocessor.recommender(list_files,query, file_dictionary)
ec_recommendation = dataprocessor.ranker(recommendation, file_vec_dict)
final_weighted_recommended = dataprocessor.weighted_final_rank(sim_list,ec_recommendation,  recommendation)
print(final_weighted_recommended)

При выполнении этого фрагмента кода выводятся следующие рекомендации вместе со значением веса для каждой из них:

[(“GAN_presentation.pptx”, 0.3 411 272 882 084 124), (“Using GANs to Augment UAV Data_V2.docx”, 0.16 293 615 818 015 078), (“GANS_DAY_1.docx”, 0.12 546 058 188 955 278), (“ml_pdf.pdf”, 0.10 864 164 490 536 887)]

Давайте попробуем еще раз. Что произойдет, если я запрошу «Машинное обучение»?

[(“ml_pdf.pdf”, 0.31 244 922 151 487 337), (“GAN_presentation.pptx”, 0.18 170 070 184 645 432), (“GANS_DAY_1.docx”, 0.14 825 501 243 059 303), (“Using GANs to Augment UAV Data_V2.docx”, 0.1 309 153 863 914 564)]

Как и ожидалось, первым рекомендуемым документом стало вводное руководство по машинному обучению! В этом примере я использовал только 7 документов, но чем больше их будет добавлено, тем больше рекомендаций вы сможете получить!

Заключение

Сегодня мы обсудили, как можно создать рекомендательную систему для файлов, которые вы храните, особенно если это исследования для вашего проекта. Ключевой особенностью этой системы является то, что она делает следующий шаг в вычислении косинусоидального подобия векторов, применяя алгоритм центральности для создания более точных и качественных рекомендаций. Попробуйте использовать эту систему (полный код) в своей работе, и я надеюсь, что она поможет вам лучше понять, насколько взаимосвязаны различные фрагменты данных, которыми вы располагаете.


Статья подготовлена в рамках онлайн-курса «NLP. Advanced». На странице курса можно ознакомиться с полной программой, а также посмотреть записи открытых уроков.

Открытые уроки в Otus проходят каждый день — переходите в календарь мероприятий и выбирайте интересующие темы.

Автор: MaxRokatansky

Источник

Рейтинг@Mail.ru
Rambler's Top100