【機(jī)器學(xué)習(xí)】從電影數(shù)據(jù)集到推薦系統(tǒng)
編譯 | VK
來(lái)源 | Towards Data Science
最初是一個(gè)數(shù)據(jù)集,現(xiàn)在是一個(gè)由Amine Zaamoun開發(fā)的電影推薦系統(tǒng):

為什么是推薦系統(tǒng)?
你們可能曾經(jīng)花上幾分鐘甚至幾個(gè)小時(shí)去選擇一部電影單獨(dú)看或者和家人一起看,不幸的是沒(méi)有成功?你希望有人在這種時(shí)候替你做決定,這正是推薦系統(tǒng)的作用。
推薦系統(tǒng)是網(wǎng)易和亞馬遜巨頭目前取得成功的主要原因之一。我設(shè)計(jì)這篇文章是為了向你展示,任何在數(shù)據(jù)科學(xué)和編程方面有一點(diǎn)創(chuàng)造力和經(jīng)驗(yàn)的人,都可以通過(guò)遵循我將要描述的幾個(gè)步驟來(lái)實(shí)現(xiàn)他們自己的推薦系統(tǒng)。
我在德國(guó)電信公司(DEUTSCHE TELEKOM AG)數(shù)據(jù)科學(xué)創(chuàng)新中心(IHUB)8個(gè)月的實(shí)習(xí)期間實(shí)現(xiàn)了這個(gè)項(xiàng)目。我們的想法也是把重點(diǎn)放在實(shí)踐方面,而不是放在理論和數(shù)學(xué)方面,你可以在互聯(lián)網(wǎng)上找到科學(xué)文獻(xiàn)。
系統(tǒng)概述和體系結(jié)構(gòu)

本文介紹的推薦系統(tǒng)分四個(gè)主要步驟實(shí)現(xiàn):
第1步:計(jì)算每部電影的加權(quán)平均分,以便向最終用戶推薦最受歡迎的100部電影的目錄
第2步:使用機(jī)器學(xué)習(xí)算法建立5部“流行”電影的推薦:使用Scikit learn的k近鄰(kNN)
第3步:建立5部由深度學(xué)習(xí)算法推薦的“鮮為人知”電影的推薦:使用Tensorflow和Keras的深度神經(jīng)矩陣分解(DNMF)實(shí)現(xiàn)
第4步:使用來(lái)自Flask(python web開發(fā)框架)部署最終系統(tǒng)
我們使用的數(shù)據(jù)集中,用戶對(duì)他們看過(guò)的電影進(jìn)行了評(píng)分。
協(xié)同過(guò)濾方法

這種方法可以基于用戶過(guò)去的行為和其他用戶做出的類似決策來(lái)構(gòu)建模型。
事實(shí)上,它是基于在數(shù)據(jù)集中選擇的電影和這些電影的評(píng)分。然后,通過(guò)預(yù)測(cè)這些電影的收視率,使用該模型來(lái)預(yù)測(cè)用戶可能感興趣的電影。
MovieLens’ ratings.csv 數(shù)據(jù)集

這個(gè)數(shù)據(jù)集中突出顯示的一行內(nèi)容如下:4號(hào)用戶觀看了21號(hào)電影,并將其評(píng)分為3.0/5.0。
有關(guān)此數(shù)據(jù)集的所有信息可以直接從以下鏈接:https://grouplens.org/datasets/movielens/latest/的README.html得到
“這個(gè)數(shù)據(jù)集[1](ml-latest-small)描述了電影推薦服務(wù)MovieLens的評(píng)分(滿分5分)和文本信息。它包含100836個(gè)收視率和3683個(gè)標(biāo)簽,涵蓋9742部電影。這些數(shù)據(jù)由610名用戶在1996年3月29日至2018年9月24日期間創(chuàng)建。該數(shù)據(jù)集于2018年9月26日生成。
用戶是隨機(jī)選擇的。所有選定的用戶都對(duì)至少20部電影進(jìn)行了評(píng)分。不包括人口統(tǒng)計(jì)信息。每個(gè)用戶都由一個(gè)id表示,不提供其他信息。”
另外請(qǐng)注意,對(duì)于本文介紹的推薦系統(tǒng),只使用了電影的評(píng)分,而沒(méi)有使用標(biāo)簽。
第1步:計(jì)算每部電影的加權(quán)平均分
這第一步的目標(biāo)是為我們推薦系統(tǒng)的最終用戶提供一個(gè)流行電影的目錄,他們可以從中選擇自己喜歡的電影。

代碼本身是非常不言自明的,唯一值得注意的元素是使用PySpark來(lái)執(zhí)行此計(jì)算。
實(shí)際上,這個(gè)庫(kù)允許使用SQL語(yǔ)言固有的“mean”和“col”函數(shù),從而促進(jìn)代碼的組織和可讀性。然而,同樣的計(jì)算在pandas庫(kù)也是完全可行的,因?yàn)閜andas庫(kù)在數(shù)據(jù)科學(xué)初學(xué)者中更受歡迎。
我們電影推薦系統(tǒng)實(shí)現(xiàn)的第一步代碼
import os
from pyspark.sql.functions import mean, col
"""路徑設(shè)置"""
data_path = os.environ['DATA_PATH']
movies_datapath = os.path.join(data_path, 'Movies/MovieLens/movies_data-100k')
trained_datapath = os.path.join(movies_datapath, 'Already_Trained')
"""加載數(shù)據(jù)集"""
ratings = spark.read.load(os.path.join(movies_datapath, 'ratings.csv'), format='csv', header=True, inferSchema=True).drop("timestamp")
movies = spark.read.load(os.path.join(movies_datapath, 'movies.csv'), format='csv', header=True, inferSchema=True)
"""計(jì)算每部電影的平均評(píng)分和評(píng)分?jǐn)?shù)量"""
df = ratings.join(movies, on="movieId")
number_ratings = df.groupBy('movieId').count()
average_ratings = df.groupBy('movieId').avg('rating')
df_ratings = average_ratings.join(number_ratings, on="movieId")
df = df.join(df_ratings, on="movieId")
mostRatedMovies = df.where("count >= 50")
"""計(jì)算每部電影的加權(quán)平均分"""
# 我們必須將'vote_count'列從字符串類型轉(zhuǎn)換為double類型(數(shù)值型),以便計(jì)算分位數(shù)
changedTypedf = mostRatedMovies.withColumn("vote_count", df["count"].cast("double"))
quantile_df = changedTypedf.approxQuantile("count", [0.75], 0)
m = quantile_df[0]
# collect()用于在驅(qū)動(dòng)程序中以數(shù)組的形式返回?cái)?shù)據(jù)集的所有元素。
mean_df = mostRatedMovies.select(mean(col('avg(rating)')).alias('mean')).collect()
C = mean_df[0]['mean']
movies_cleaned_df = mostRatedMovies.withColumn("weighted_average", ((mostRatedMovies['avg(rating)']*mostRatedMovies['count']) + (C*m)) / (mostRatedMovies['count']+m))
"""將表保存到CSV文件中以供以后訪問(wèn)"""
movies_cleaned_pd.to_csv(os.path.join(trained_datapath, 'MostPopularMovies.csv'), index=False)
第2步:使用k近鄰(kNN)設(shè)置5部“流行”電影的推薦
第2步的目標(biāo)是向最終用戶推薦一系列可以稱為“流行”的電影。
首先,它幫助用戶放心,因?yàn)樗辽贂?huì)認(rèn)出推薦的電影之一。事實(shí)上,如果他不認(rèn)識(shí)任何推薦的電影,他可能會(huì)拒絕我們系統(tǒng)的有用性。不幸的是,這一心理和人的因素是無(wú)法量化的。這也證明,如果不考慮文化方面,最好的數(shù)學(xué)和統(tǒng)計(jì)模型可能不適合一些用戶。
其次,使用kNN算法推薦的電影都是“流行”的,這是在訓(xùn)練機(jī)器學(xué)習(xí)模型之前對(duì)數(shù)據(jù)進(jìn)行預(yù)先過(guò)濾的直接結(jié)果。
事實(shí)上,我們數(shù)據(jù)集中的評(píng)估頻率遵循“長(zhǎng)尾”分布。這意味著大多數(shù)電影的收視率非常低,而“少數(shù)壓倒性”的收視率遠(yuǎn)遠(yuǎn)高于其他電影的總和。因此,這個(gè)過(guò)濾器只允許使用最流行的電影來(lái)訓(xùn)練kNN算法,因此得到的推薦也只能是流行電影。
該算法還具有易于理解和解釋的優(yōu)點(diǎn)。對(duì)于非技術(shù)人員來(lái)說(shuō)尤其如此,比如你公司的銷售團(tuán)隊(duì),或者僅僅是你的朋友和家人,他們不一定對(duì)數(shù)據(jù)科學(xué)十分理解。
Kevin Liao在文章中所解釋的:“當(dāng)KNN對(duì)一部電影進(jìn)行推斷時(shí),KNN將計(jì)算目標(biāo)電影與其數(shù)據(jù)庫(kù)中其他每部電影之間的‘距離’,然后對(duì)其距離進(jìn)行排序,并返回前K個(gè)最近鄰居電影作為最相似的電影推薦”。


正如你在本例中所看到的,與“鋼鐵俠(2008)”最接近的電影是“黑暗騎士(2008)”,其余弦相似性(或簡(jiǎn)稱“距離”)約為0.33。
這個(gè)結(jié)果,從主觀和個(gè)人的角度來(lái)看,似乎非常連貫的意義上說(shuō),他們是兩個(gè)超級(jí)英雄電影。我們還可以注意到《阿凡達(dá)(2009)》和《盜夢(mèng)空間(2010)》這兩部科幻電影的出現(xiàn)。
我感謝有必要注意到機(jī)器學(xué)習(xí)算法的魔力,因?yàn)檎缥姨嵝涯愕哪菢?,只使用?.0到5.0的評(píng)分。事實(shí)上,這些電影的類型并沒(méi)有被用來(lái)提供這些建議。
下面是相關(guān)的代碼片段,向你展示如何使用Scikit學(xué)習(xí)庫(kù)實(shí)現(xiàn)此算法,并根據(jù)選定的電影標(biāo)題獲取建議
我們的電影推薦系統(tǒng)實(shí)現(xiàn)的第2步中的kNN算法片段:
from scipy.sparse import csr_matrix
from sklearn.neighbors import NearestNeighbors
import numpy as np
import pandas as pd
"""創(chuàng)建透視表"""
movies_pivot = mostRatedMovies.groupBy('title').pivot('userId').sum('rating').fillna(0)
movie_features_df = movies_pivot.toPandas().set_index('title')
movie_features_df_matrix = csr_matrix(movie_features_df.values)
"""使用整個(gè)數(shù)據(jù)集擬合最終的無(wú)監(jiān)督模型,以找到每一個(gè)最相似的電影"""
model_knn = NearestNeighbors(metric='cosine', algorithm='brute', n_neighbors=11, n_jobs=-1)
model_knn.fit(movie_features_df_matrix)
# 選擇一個(gè)標(biāo)題
favoriteMovie = 'Iron Man (2008)'
query_index = movie_features_df.index.get_loc(favoriteMovie)
distances, indices = model_knn.kneighbors(movie_features_df.loc[favoriteMovie,:].values.reshape(1, -1), n_neighbors=11)
# 根據(jù)kNN模型打印10部最相似的電影
for i in range(0, len(distances.flatten())):
if i == 0:
print('Recommendations for {0}:\n'.format(movie_features_df.index[query_index]))
else:
print('{0}: {1}, with distance of {2}:'.format(i, movie_features_df.index[indices.flatten()[i]], distances.flatten()[i]))
第3步:使用深層神經(jīng)矩陣分解(DNMF)建立5部“鮮為人知”電影的推薦
第3步的目的和該算法的選擇是向最終用戶推薦一系列往往“鮮為人知”的電影。
不需要過(guò)多的細(xì)節(jié),只需要記住,不需要預(yù)先過(guò)濾,而且電影可以用作訓(xùn)練數(shù)據(jù),而不管它的受歡迎程度如何。
實(shí)際上,這個(gè)算法在數(shù)學(xué)上非常復(fù)雜,它結(jié)合了數(shù)據(jù)科學(xué)中常用的兩個(gè)模型。第一個(gè)模型是矩陣分解,例如,交替最小二乘(ALS)算法。另一個(gè)模型是深層神經(jīng)網(wǎng)絡(luò)的一個(gè)例子,例如多層感知器(MLP)。
寫一整篇文章來(lái)正確地解釋它必要的,但正如我之前已經(jīng)宣布,目標(biāo)是是偏向于實(shí)現(xiàn)。因此,我讓你閱讀這兩篇已經(jīng)很好地解釋了這些概念的參考資料:(https://towardsdatascience.com/prototyping-a-recommender-system-step-by-step-part-2-alternating-least-square-als-matrix-4a76c58714a1;https://towardsdatascience.com/building-a-deep-learning-model-using-keras-1548ca149d37)
第3步中使用的深層神經(jīng)矩陣分解算法(DNMF)具有以下體系結(jié)構(gòu):

該算法的原理與經(jīng)典的矩陣分解相同。使用這個(gè)模型,我們?cè)噲D預(yù)測(cè)某個(gè)用戶對(duì)某部電影的評(píng)價(jià)。我指定了“他會(huì)給出”的評(píng)分,因?yàn)檫@個(gè)算法填充了當(dāng)前數(shù)據(jù)存在的空白值。
讓我解釋一下:即使是一個(gè)大影迷也可能沒(méi)有看過(guò)或評(píng)價(jià)過(guò)我們數(shù)據(jù)集中的所有9742部電影。這樣一來(lái),他就可以給自己還沒(méi)有打分的電影打分,以此來(lái)決定自己是否喜歡這些電影。這正是我們算法的矩陣分解部分所做的。
神經(jīng)網(wǎng)絡(luò)的加入使得進(jìn)一步提高模型的預(yù)測(cè)性能成為可能,從而減少預(yù)測(cè)和實(shí)際評(píng)分之間的誤差。下面是一個(gè)代碼片段,向你展示如何使用Tensorflow和Keras庫(kù)實(shí)現(xiàn)這樣的模型。我們將使用它來(lái)預(yù)測(cè)與一對(duì)不存在的(userId,movieId)的評(píng)分。
我們的電影推薦系統(tǒng)實(shí)現(xiàn)的第三步中的DNMF算法片段
import numpy as np
import pandas as pd
from tensorflow import keras
"""計(jì)算不同userid和movieid的數(shù)量,創(chuàng)建輸入用戶和電影向量和潛在因子的數(shù)量"""
n_users = len(df_ratings_reduced["userId"].unique())
n_movies = len(df_ratings_reduced["movieId"].unique())
userIds_vector = np.asarray(df_ratings.userId).astype(np.int32)
movieIds_vector = np.asarray(df_ratings.movieId).astype(np.int32)
n_latent_factors = 20
"""實(shí)現(xiàn)模型架構(gòu),并使其擬合到輸入用戶和電影向量"""
# 用戶矩陣分解和多層感知機(jī)嵌入路徑
users_input = keras.layers.Input(shape=[1], dtype='int32', name="users_input")
users_mf_embedding = keras.layers.Embedding(input_dim=n_users + 1, output_dim=n_latent_factors, name='users_mf_embedding')
users_flattened_mf = keras.layers.Flatten()(users_mf_embedding(users_input))
users_mlp_embedding = keras.layers.Embedding(input_dim=n_users + 1, output_dim=n_latent_factors, name='users_mlp_embedding')
users_flattened_mlp = keras.layers.Flatten()(users_mlp_embedding(users_input))
# 矩陣分解和多層感知機(jī)嵌入路徑
movies_input = keras.layers.Input(shape=[1], dtype='int32', name="movies_input")
movies_mf_embedding = keras.layers.Embedding(input_dim=n_movies + 1, output_dim=n_latent_factors, name='movies_mf_embedding')
movies_flattened_mf = keras.layers.Flatten()(movies_mf_embedding(movies_input))
movies_mlp_embedding = keras.layers.Embedding(input_dim=n_movies + 1, output_dim=n_latent_factors, name='movies_mlp_embedding')
movies_flattened_mlp = keras.layers.Flatten()(movies_mlp_embedding(movies_input))
# 用戶與電影的點(diǎn)積矩陣分解嵌入和連接用戶與電影的多層感知機(jī)嵌入
interaction_matrix = keras.layers.Dot(name="interaction_matrix", axes=1)([movies_flattened_mf, users_flattened_mf])
concatenation_vector = keras.layers.Concatenate(name="concatenation_vector")([movies_flattened_mlp, users_flattened_mlp])
# 添加全連接層,矩陣分解和多層感知機(jī)部分的連接和輸出層
dense_1 = keras.layers.Dense(50, activation='elu', kernel_initializer="he_normal")(concatenation_vector)
dense_2 = keras.layers.Dense(25, activation='elu', kernel_initializer="he_normal")(dense_1)
dense_3 = keras.layers.Dense(12, activation='elu', kernel_initializer="he_normal")(dense_2)
dense_4 = keras.layers.Dense(6, activation='elu', kernel_initializer="he_normal")(dense_3)
dense_5 = keras.layers.Dense(3, activation='elu', kernel_initializer="he_normal")(dense_4)
final_concatenation = keras.layers.Concatenate(name="final_concatenation")([interaction_matrix, dense_5])
output_layer = keras.layers.Dense(1)(final_concatenation)
# 拼接輸入輸出,編譯模型
dnmf_model_final = keras.models.Model(inputs=[users_input, movies_input], outputs=output_layer)
dnmf_model_final.compile(loss="mean_squared_error", optimizer=keras.optimizers.SGD(lr=0.01, momentum=0.9, nesterov=True, clipvalue=1.0), metrics=[keras.metrics.RootMeanSquaredError()])
# 擬合模型
history = dnmf_model_final.fit([userIds_vector, movieIds_vector], ratings_vector, epochs=100)
"""生成與尚未存在的(userId, movieId)的預(yù)測(cè)評(píng)分,將用于進(jìn)一步的推薦"""
# 選擇一個(gè)不存在于ratings.csv文件中的(userId, movieId)對(duì),例如(1,10)
userIdChosed_vector = np.asarray([1]).astype(np.int32)
movieIdChosed_vector = np.asarray([10]).astype(np.int32)
# 根據(jù)DNMF模型預(yù)測(cè)userid_chosen將給movieid_chosen的評(píng)分
predicted_rating = dnmf_model_final.predict([userIdChosed_vector, movieIdChosed_vector])
print(predicted_rating)
現(xiàn)在,我們可以按照同樣的邏輯來(lái)預(yù)測(cè)我們數(shù)據(jù)庫(kù)中所有尚未存在的(userId,movieId)。以用戶401為例,通過(guò)DNMF算法計(jì)算出前10位如下:

現(xiàn)在,我們可以將使用此模型生成的兩個(gè)表的結(jié)果保存在兩個(gè)不同的csv文件中:為每個(gè)電影推薦的前10個(gè)用戶和為每個(gè)用戶推薦的前10個(gè)電影。
pdUserRecs.to_csv(os.path.join(trained_datapath, 'DNMF_MovieRecommendationsForAllUsers.csv'), index=False)
pdMovieRecs.to_csv(os.path.join(trained_datapath, 'DNMF_UserRecommendationsForAllMovies.csv'), index=False)
第4步:使用Flask部署最終系統(tǒng)
我們終于到了最后一步,這一步需要對(duì)web開發(fā)略知一二。
將系統(tǒng)作為一個(gè)真正的應(yīng)用程序進(jìn)行適當(dāng)?shù)牟渴饘⒎浅S杏?。在這個(gè)web應(yīng)用程序中,我們將鏈接本文前面步驟中完成的所有工作。
實(shí)際上,用戶將從100部最受歡迎電影的目錄中選擇3部電影開始,并且這些電影是根據(jù)第一步中這些電影的加權(quán)平均分計(jì)算出來(lái)的。
這3部電影將作為我們的2個(gè)模型的輸入數(shù)據(jù),以獲得10部電影的最終推薦,其中5部來(lái)自kNN,5部來(lái)自DNMF。
此外,為了給最終用戶提供快速而流暢的體驗(yàn),已經(jīng)預(yù)先計(jì)算了DNMF模型將給出的預(yù)測(cè)。
這意味著對(duì)于選中的3部電影中的每一部,系統(tǒng)都會(huì)在“DNMF_UserRecommendationsForAllMovies”中進(jìn)行搜索。根據(jù)預(yù)測(cè)得分“匹配”5個(gè)用戶:

然后,系統(tǒng)將使用此匹配的用戶列表重復(fù)與前面相同的過(guò)程。
換言之,它將在另一個(gè)列表中添加每個(gè)用戶最喜愛(ài)的5部電影,其中5部將使用另一個(gè)表保存在最后。
這允許我們基于類似的用戶配置文件向用戶提供電影推薦。另一個(gè)非常重要的一點(diǎn)是,這些建議已經(jīng)快速和準(zhǔn)確地給出,而不必等待數(shù)小時(shí)的模型進(jìn)行重新訓(xùn)練,因此預(yù)先計(jì)算DNMF結(jié)果十分有用。
@app.route('/recommended_movies', methods=['POST'])
def make_recommendations():
finalRecommendations = []
popular_movies_list = show_popular_movies(mostPopularMovies)
favorite_movieTitles = request.form.getlist('cb')
favorite_ids = get_movieIds(movies, favorite_movieTitles)
popular_movieIds_list = get_movieIds(movies, popular_movies_list)
# 對(duì)于用戶選擇的每一部最喜歡的電影,將他們最近的10部電影添加到kNN_recommendations列表中,隨機(jī)保留5部
kNN_recommendations = []
for i in range(3):
userMovie = favorite_movieTitles[i]
query_index = kNNmovieMatrix.index.get_loc(userMovie)
distances, indices = loaded_kNN_model.kneighbors(kNNmovieMatrix.iloc[query_index,:].values.reshape(1, -1), n_neighbors = 11)
for j in range(1, len(distances.flatten())):
movieTitle = kNNmovieMatrix.index[indices.flatten()[j]]
distance = distances.flatten()[j]
if (movieTitle not in popular_movies_list) and (movieTitle not in kNN_recommendations) and (movieTitle not in favorite_movieTitles):
kNN_recommendations.append(movieTitle)
final_kNN_recommendations = random.sample(kNN_recommendations, 5)
kNN_recommendedIds = get_movieIds(movies, final_kNN_recommendations)
# 對(duì)于用戶選擇的每個(gè)最喜歡的電影,將他們推薦的前5個(gè)用戶添加到DNMF_usersRecommendation列表中
DNMF_usersRecommendation = []
for i in range(3):
movieChosed = favorite_ids[i]
for j in range(5):
userRecommended = pdMovieRecs[pdMovieRecs.movieId == movieChosed]["userRecommendations"].iloc[0][j]
predictedMatch = pdMovieRecs[pdMovieRecs.movieId == movieChosed]["userRatings"].iloc[0][j]
if (userRecommended not in DNMF_usersRecommendation):
DNMF_usersRecommendation.append(userRecommended)
# 對(duì)于模型推薦的每個(gè)用戶,將他們推薦的前5部電影添加到DNMF_moviesRecommendation列表中,并隨機(jī)保留5部
DNMF_moviesRecommendation = []
for i in range(len(DNMF_usersRecommendation)):
userChosed = DNMF_usersRecommendation[i]
for j in range(5):
movieRecommended = pdUserRecs[pdUserRecs.userId == userChosed]["movieRecommendations"].iloc[0][j]
predictedRating = pdUserRecs[pdUserRecs.userId == userChosed]["movieRatings"].iloc[0][j]
if (movieRecommended not in DNMF_moviesRecommendation) and (movieRecommended not in kNN_recommendedIds) and (movieRecommended not in favorite_ids) and (movieRecommended not in popular_movieIds_list):
DNMF_moviesRecommendation.append(movieRecommended)
final_DNMF_recommendations = random.sample(DNMF_moviesRecommendation, 5)
recommendedMovieTitles = get_movieTitles(movies, final_DNMF_recommendations)
# 加入兩個(gè)列表,以便從kNN模型給出5部電影推薦和從DNMF模型給出5部電影推薦
finalRecommendations = final_kNN_recommendations + recommendedMovieTitles
recommendedMoviePosters = get_moviePosters(movies, finalRecommendations)
return render_template('index.html',
choose_message="Here is a list of the most popular movies in our database, please choose 3 :",
favorite_movies_message="Your 3 favorite movies are :",
favorite_movies_list=favorite_movieTitles,
recommendations_message="We recommend you the following movies :",
recommendations_list=finalRecommendations,
recommendations_posters=recommendedMoviePosters)
正如你所注意到的,當(dāng)用戶選擇了他的3部電影并按下按鈕以獲得他的推薦時(shí),POST請(qǐng)求被發(fā)送到服務(wù)器。處理此請(qǐng)求時(shí),呈現(xiàn)的函數(shù)將返回幾個(gè)與“模板”關(guān)聯(lián)的變量。下面是如何在index.html讀取變量:
<div id="recommendationsDiv">
{{ favorite_movies_message}}
<ul>
{% for favorite_movie in favorite_movies_list %}
<li>{{ favorite_movie }}</li>
{% endfor %}
</ul>
{{ recommendations_message }}
<br><br>
{% if (recommendations_list is defined) and (recommendations_posters is defined) %}
<img src="{{ recommendations_posters[0] }}" alt="{{ recommendations_list[0] }}" />
<p>{{ recommendations_list[0] }}</p><br><br>
<img src="{{ recommendations_posters[1] }}" alt="{{ recommendations_list[1] }}" />
<p>{{ recommendations_list[1] }}</p><br><br>
<img src="{{ recommendations_posters[2] }}" alt="{{ recommendations_list[2] }}" />
<p>{{ recommendations_list[2] }}</p><br><br>
<img src="{{ recommendations_posters[3] }}" alt="{{ recommendations_list[3] }}" />
<p>{{ recommendations_list[3] }}</p><br><br>
<img src="{{ recommendations_posters[4] }}" alt="{{ recommendations_list[4] }}" />
<p>{{ recommendations_list[4] }}</p><br><br>
<img src="{{ recommendations_posters[5] }}" alt="{{ recommendations_list[5] }}" />
<p>{{ recommendations_list[5] }}</p><br><br>
<img src="{{ recommendations_posters[6] }}" alt="{{ recommendations_list[6] }}" />
<p>{{ recommendations_list[6] }}</p><br><br>
<img src="{{ recommendations_posters[7] }}" alt="{{ recommendations_list[7] }}" />
<p>{{ recommendations_list[7] }}</p><br><br>
<img src="{{ recommendations_posters[8] }}" alt="{{ recommendations_list[8] }}" />
<p>{{ recommendations_list[8] }}</p><br><br>
<img src="{{ recommendations_posters[9] }}" alt="{{ recommendations_list[9] }}" />
<p>{{ recommendations_list[9] }}</p>
{% endif %}
</div>
以下是最終結(jié)果:

就這樣!你現(xiàn)在可以嘗試實(shí)現(xiàn)你自己的系統(tǒng)版本了。
總結(jié)
在本文中,我們共同了解了如何使用Python編程語(yǔ)言將一個(gè)簡(jiǎn)單的數(shù)據(jù)集轉(zhuǎn)換為一個(gè)真正的電影推薦系統(tǒng),并將其部署為一個(gè)web應(yīng)用程序。
我們還了解到,推薦系統(tǒng)通?;诓煌幕ミB算法。這對(duì)于為每種類型的產(chǎn)品(無(wú)論是“流行的”還是“鮮為人知的”)提供建議確實(shí)很有用。
我盡我所能以一種更實(shí)際而非理論的方式來(lái)表達(dá)這個(gè)話題,這樣任何人都能理解我在說(shuō)什么,希望你喜歡。源代碼可以在我的GitHub找到:https://github.com/Zaamine/Movie_Recommender_System-Python
參考引用
[1] F. Maxwell Harper and Joseph A. Konstan. The MovieLens Datasets: History and Context (2015), ACM Transactions on Interactive Intelligent Systems (TiiS) 5, 4: 19:1–19:19.
往期精彩回顧
本站qq群851320808,加入微信群請(qǐng)掃碼:
