Часть 3. Создание и развертывание рекомендательной системы

Привет!

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

Теперь, наконец, мы перейдем к построению рекомендательной системы. Мы будем использовать косинусное сходство для построения нашей рекомендательной системы.

Here's a breakdown of steps we will be performing in this article:

1. Building a Recommender system

2. Building Our App for the Recommender System

3. Deploying App on Hugging Face

Conclusion

1. Создание системы рекомендаций

#removing stopwords
tfidf = TfidfVectorizer(stop_words='english')

#get the tf-idf scores
#create TF-IDF matrix by fitting and transforming the data
tfidf_matrix = tfidf.fit_transform(data['org_new'])

#shape of tfidf_matrix
tfidf_matrix.shape

Во-первых, мы создали объект tf-idf, которому мы присвоили функцию TfidfVectorizer нашему объекту tfidf, и указали стоп-слова как «английские» для дальнейшей проверки и удаления существующих стоп-слов.

Затем мы создали матрицу tf-idf, в которой мы сохранили наши данные, затем, наконец, мы проверили форму наших данных, и вы будете шокированы, увидев, что теперь у нас есть 7770 наблюдений и 41973 столбца. Это потому, что у нас есть один столбец для каждого слова с их оценками tfidf.

Теперь давайте воспользуемся косинусным сходством для построения нашей рекомендательной системы:

Почему косинусное сходство?

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

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

Использование подобия косинусов

Косинусное сходство — это мера сходства между двумя ненулевыми векторами в многомерном пространстве. Он измеряет косинус угла между двумя векторами, который находится в диапазоне от -1 (противоположные направления) до 1 (одно направление), где 0 указывает на ортогональность (векторы перпендикулярны друг другу).

Он используется для определения того, насколько похожи два документа или фрагмента текста. Мы представили документы как векторы в многомерном пространстве, где каждое измерение представляет слово или термин в корпусе.

Затем мы можем вычислить косинусное сходство между векторами, чтобы определить, насколько похожи документы (документ относится к анализируемому фрагменту текста) на основе их словоупотребления.

from sklearn.metrics.pairwise import cosine_similarity
cosine_sim = cosine_similarity(tfidf_matrix) #applying cosine similarity to tfidf_matrix
programme_list=new_df['title'].to_list() #creating list of movies and tv shows
def recommend(title, cosine_similarity=cosine_sim):
    index = programme_list.index(title)         #finds the index of the input title in the programme_list.
    sim_score = list(enumerate(cosine_sim[index])) #creates a list of tuples containing the similarity score and index of the input title and all other programmes in the dataset.
    
    #position 0 is the movie itself, thus exclude
    sim_score = sorted(sim_score, key= lambda x: x[1], reverse=True)[1:11]  #sorts the list of tuples by similarity score in descending order.
    recommend_index = [i[0] for i in sim_score]  #selecting index of recommended movies
    rec_movie = new_df['title'].iloc[recommend_index]
    rec_score = [round(i[1],4) for i in sim_score]
    rec_table = pd.DataFrame(list(zip(rec_movie,rec_score)), columns=['Recommended movie','Similarity(0-1)'])
    return rec_table

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

Если вы не поняли приведенный выше код, попробуйте разбить его построчно, а затем попробуйте запустить его в своей системе и проверьте, что выводит каждая строка. Вот так можно объяснить себе что-то 😉.

Итак, теперь давайте проверим, как работает наша рекомендательная система:

recommend("Indiana Jones and the Last Crusade")

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

recommend('Zindagi Na Milegi Dobara')

Это 10 лучших рекомендаций, связанных с фильмом Zindagi Na Milegi Dobara. Вы также можете увидеть оценки сходства фильма с другими фильмами в таблице.

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

Что ж, приступим без промедления!

2. Создание нашего приложения для системы рекомендаций

Помните new_df из нашего второго сезона? Да, его характер был не там; он играет важную роль и в этом сезоне.

Мы сохраняем new_df и cosine_sim в файле рассола для дальнейшей обработки. Сохранение этих вещей в файле pickle позволяет нам хранить обученную модель или данные в файле, к которому можно легко получить доступ и загрузить позже без повторного обучения модели.

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

Мы использовали метод pickle.dump() для создания дампа нашего фрейма данных, преобразовав его в словарь с помощью функции to_dict() (мы преобразовываем его в словарь, потому что ранее произошла некоторая ошибка при непосредственном сохранении и загрузке набора данных).

import pickle
pickle.dump(new_df.to_dict(), open('movie_dict.pkl', 'wb'))
import pickle
pickle.dump(cosine_sim, open('cosine_sim.pkl', 'wb'))

Итак, теперь у нас есть все необходимое для создания нашего приложения. Приступаем к кодированию:

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

Затем откройте Visual Studio Code или любую другую IDE, где вы можете написать код, выберите параметр файла в верхнем левом углу, затем выберите «Открыть папку». Затем перейдите на рабочий стол и выберите свою папку, рекомендательное приложение.

Там создайте новый файл с именем app.py и начните писать следующий код в app.py:

Импорт необходимых библиотек

import streamlit as st #this is the framework in python that we will use to build app
import pickle 
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.feature_extraction.text import CountVectorizer
from imdb import IMDb 

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

Чтобы использовать эту платформу, вам может потребоваться установить библиотеку imdbpy с помощью этой команды:

pip install IMDbPY

Вот ссылка на документацию этой библиотеки, на которую вы можете ссылаться:



Загрузка файлов рассола

similarity = pickle.load(open('cosine_sim.pkl', 'rb')) #loading our cosine_sim pickle file
movie_dict = pickle.load(open('movie_dict.pkl', 'rb')) #loading our movie_dict file 
movies = pd.DataFrame(movie_dict)

programme_list=movies['title'].to_list()

Здесь мы загрузили наши файлы pickle в две переменные с именами similarity и movie_dict. Затем мы преобразовали наш словарь movie_dict в фрейм данных, используя функцию pd.DataFrame() в pandas.

Затем мы создали список всех фильмов с их названиями и сохранили их в переменной с именем programme_list.

Написание кода для получения информации с IMDb

imdb = IMDb()
def get_movie_id(movie_title):

    """ To Get the IMDb ID of the movie using the IMDbPY library."""

    try:
        movies = imdb.search_movie(movie_title) #searching the movie with it'a name
        movie_id = movies[0].getID()  # get the ID of the first search result
        return movie_id #returning movie id from imdb database

    except Exception as e:
        st.error("Error: Failed to retrieve IMDb ID for the selected movie. Please try again with a different movie.")
        st.stop() #this will stop the app working

    ##If the movie is not present on imdb then this error message will show up on the app
    ## st.error method is used to display this message


def get_poster_url(imdb_id):

    """To Get the URL of the poster image of the movie."""

    try:

        movie = imdb.get_movie(imdb_id) #Here we are using the get_movie method
        #to fetch all information related to movie in a variable named movie

        poster_url = movie['full-size cover url'] #getting poster url using 'full-size cover url', do not edit it toherwise you won't get the poster
        return poster_url

    except Exception as e:
        st.error("Error: Failed to retrieve poster URL for the selected movie. Please try again with a different movie.")
        st.stop()
    ##In case the poster is not present for the movie our app will display this message to the end user

Обработка исключений всегда является важной и хорошей практикой при создании приложения. Известные операторы try-except в Python используются для обработки исключений здесь, в приведенном выше коде.

Чтобы узнать больше об обработке исключений, ознакомьтесь с документацией по Python здесь:



Создание функции рекомендации фильмов

def recommend(movie):
    index = programme_list.index(movie)         
    sim_score = list(enumerate(similarity[index])) #creates a list of tuples containing the similarity score and index between the input title and all other programmes in the dataset.
    
    #position 0 is the movie itself, thus exclude
    sim_score = sorted(sim_score, key= lambda x: x[1], reverse=True)[1:6]  #sorts the list of tuples by similarity score in descending order, and selecting the top 5 movies with high similarity score
    recommend_index = [i[0] for i in sim_score] #selecting index of recommended movies
    rec_movie = movies['title'].iloc[recommend_index] #getting the movie name
    rec_movie_ids = [get_movie_id(title) for title in rec_movie] #getting movie ids from imdb by applying our prewritten function get_movie_id
   
    return rec_movie, rec_movie_ids

Давайте разберемся с работой этой рекомендательной функции на примере истории:

Когда-то в Python была функция под названием «рекомендовать». Эта функция была разработана, чтобы помочь любителям кино найти новые фильмы для просмотра, рекомендуя похожие фильмы на основе их предпочтений.

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

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

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

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

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

В целом, функция «рекомендовать» была мощным инструментом для любителей кино, которые искали новые фильмы для просмотра, поскольку она могла быстро и точно рекомендовать похожие фильмы на основе их предпочтений.

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

Создание пользовательского интерфейса приложения

st.set_page_config(page_title='Movie Recommender System', page_icon=':clapper:', layout='wide') #setting the configuration of the app
st.title('Movie Recommender System') #Making our title for the webpage using st.title

#note that we have imported streamlit as st already

selected_movie_name = st.selectbox('Please select a Movie',
sorted(movies['title'].values))

'''Making a select box so that user can navigate and select the movies they want
to get recommendations for. We have passed all the movie names to this select box n
in a sorted manner by getting the values of all titles from our dataframe named
movies.
'''

Вы также можете запустить код, сохранив файл и применив эту команду на терминале — streamlit run app.py.

И вы увидите, что сайт открывается на локальном сервере.

Если он выдает ошибку или пустую веб-страницу, то проверьте, установили ли вы все зависимости в терминале или нет (например, используйте для этого pip install).

А затем попробуйте перезапустить код с помощью команды — streamlit run app.py.

Вот так будет выглядеть наше приложение, оно может сразу выглядеть менее привлекательным, но вы оцените его, когда оно будет давать рекомендации с постерами. Мы также увидим результаты в конце. Хотя спойлеры можно листать вниз😜.

if st.button('Recommend Me'): #st.button used to create button below our title
    try:

        recommendations, rec_movie_ids = recommend(selected_movie_name)
        # st.write(recommendations, rec_movie_ids)
        # st.write(recommendations[6195])
        #These above 2 codes I used to check the output of my code in written
        # format, you can also play around with it. I did this to check and rectify my errors

        final_movie_names = [] #creating an empty list
        for i, rec_id in zip(recommendations, rec_movie_ids): #zip function used to iterate over two lists in parallel  
            final_movie_names.append(i)  #appending movie names to the list
            # st.write(i)
            # poster_url = get_poster_url(rec_id)
            # st.image(poster_url)


        col1, col2, col3, col4, col5 = st.columns(5)
        #cols = [col1, col2, col3, col4, col5] again, this code is not necessary, I just used to try something else

        with col1:
            st.text(final_movie_names[0])
            poster_url = get_poster_url(rec_movie_ids[0])
            st.image(poster_url)
        with col2:
            st.text(final_movie_names[1])
            poster_url = get_poster_url(rec_movie_ids[1])
            st.image(poster_url)
        with col3:
            st.text(final_movie_names[2])
            poster_url = get_poster_url(rec_movie_ids[2])
            st.image(poster_url)
        with col4:
            st.text(final_movie_names[3])
            poster_url = get_poster_url(rec_movie_ids[3])
            st.image(poster_url)
        with col5:
            st.text(final_movie_names[4])
            poster_url = get_poster_url(rec_movie_ids[4])
            st.image(poster_url)
    except Exception as e:
        st.write('An error occurred while generating recommendations:', e)

recommendations — сохраняет название фильма

rec_movie_ids — сохраняет идентификатор фильма

Наш макет состоит из пяти столбцов: col1, col2, col3, col4 и col5. Где в каждом столбце отображается информация о рекомендуемом фильме.

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

Затем мы создали блок with, указывающий, что первый столбец (col1) будет использоваться для отображения информации о первом рекомендованном фильме. В этом блоке отображается название первого рекомендованного фильма с помощью функции st.text. Функция отображает строковый аргумент в виде текста в пользовательском интерфейсе.

Затем мы использовали функцию get_poster_url для получения URL-адреса постера для первого рекомендуемого фильма. Этот URL назначается переменной poster_url.

Наконец, мы использовали функцию st.image для отображения постера первого рекомендуемого фильма в первом столбце макета. Он принимает аргумент URL-адреса и отображает изображение по URL-адресу в пользовательском интерфейсе.

Точно так же остальная часть кода работает одинаково до блока with для col5.

Затем мы снова использовали обработку ошибок, чтобы избежать ошибок.

Теперь нам также нужно создать файл requirements.txt, содержащий все библиотеки, необходимые для развертывания нашего приложения. В папке на рабочем столе создайте новый текстовый файл с именем requirements.txt и введите в него следующие зависимости:

streamlit
sklearn
pandas
scikit-learn==1.0.2
imdbpy

Символ == используется для указания точного номера версии каждой устанавливаемой зависимости.

Существует также другой метод, с помощью которого мы можем создать этот файл requirements.txt, введя всего одну строку кода в нашем терминале (вы должны запустить его в правильном каталоге, где хранятся все ваши файлы) pip install -r requirements.txt.

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

Окончательно! Теперь мы можем сохранить наш файл app.py и проверить веб-сайт, который выглядит так с выводом и без него.

До

После

Большой! Наше приложение работает. Поздравляем нас. Наконец-то мы это сделали.🏆

Я ценю, что вы потратили время на эту статью, и я надеюсь, что вы узнали что-то новое.

3. Развертывание приложения на обнимающемся лице

Ну, мы еще не закончили. Давайте развернем это приложение на платформе Hugging Face:

Вот еще статья:



Создайте учетную запись и перейдите в «Пространства» в верхней правой части веб-сайта, затем выберите «Создать новое пространство».

Выберите имя для своего пространства, выберите дополнительную лицензию, затем установите видимость вашего пространства, и вам будет предложено выбрать SDK для вашего пространства.

SDK означает комплект для разработки программного обеспечения. В Hugging Face Spaces SDK относится к набору инструментов и библиотек, которые мы можем использовать для программного взаимодействия с платформой Hugging Face Spaces. Платформа предлагает четыре варианта SDK: Gradio, Streamlit, Docker и статический HTML.

Вы можете выбрать SDK как Streamlit, поскольку мы создали наше приложение в Streamlit.

Затем нажмите «Создать пространство»:

Там вы увидите пункт меню с надписью «файлы и версии» на экране. Нажмите на эту опцию, чтобы перейти к разделу файлов и версий вашей рабочей области. Здесь вы можете загрузить все необходимые файлы для вашего проекта, включая app.py, notebook.py, dataset.py, cosine_sim.pkl, movie_dict.pkl и requirement.txt.

Эти файлы должны быть загружены в соответствующее место (в разделе файлов и версий в вашем пространстве) в вашем пространстве на Hugging Face, чтобы они были легко доступны и могли использоваться для запуска проекта.

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

Теперь вернитесь в раздел приложения в своем пространстве и дайте ему некоторое время, пока оно не развернет вашу модель.

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

Заключение

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

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

И так, чего же ты ждешь? Поделитесь своим приложением с друзьями и революционизируйте совместный просмотр фильмов!

Если вы хотите проверить полный код с файлами pickle, app.py и наборами данных, вы можете проверить мой репозиторий GitHub:

Репозиторий GitHub



Те, кто плохо знаком с этой серией, могут ознакомиться с нашим сезоном 1 и сезоном 2.

ссылка на 1 сезон



ссылка на 2 сезон



Ссылка на рабочее приложение



Поскольку мы заканчиваем эту захватывающую серию о кластеризации телешоу Netflix и системе рекомендаций развертыванием на Hugging Face, я надеюсь, что вы нашли ее информативной, проницательной и приятной.

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

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

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