继续创造,加速生长!这是我参加「日新计划 10 月更文应战」的第19天,点击查看活动概况

前语

引荐体系在用户发现中起主要作用。假定,咱们具有数千种不同的产品,每种产品还存在不同的规格、款式等。在这种情况下,对用户进行有关产品的精准引荐将成为添加销量的要害。在本节中,咱们将以电影引荐体系为例介绍引荐体系模型构建的办法,从而为用户引荐其真正感兴趣的产品。

模型与数据集剖析

在本节中,咱们将学习如何依据用户对电影的评分数据库构建电影引荐体系,使命目的是最大极限地进步所引荐电影对用户的相关性。在界说方针时,咱们还应该考虑引荐的电影虽然相关,但用户或许并不会立即观看。一起,咱们还应该保证所有的引荐并不都是关于同一种类型的,这对于引荐体系至关重要,例如,在零售环境中,咱们并不期望一向向用户引荐不同规格的同一种产品。
归纳以上剖析,咱们能够形式化地界说咱们的方针和束缚条件:

  • 方针:最大极限地进步引荐与用户的相关性
  • 束缚:添加引荐的多样性,并向用户供给最多 12 条引荐主张

相关性的界说在不同使命中或许会有所不同,通常需求以实际事务需求为指导。在本使命中,咱们狭义地界说相关性,也就是说,假如用户采用了向用户引荐的前 12 条主张中的任何一个,则以为引荐成功相关。

数据集剖析

用于模型练习的数据集中包括用户信息以及他们对其观看过的电影评分信息,其中第一列表明用户编号,第二列表明电影编号,第三列表明用户对电影的评分,最终一列表明时刻戳。

模型剖析

在完成电影引荐体系前,咱们首要梳理构建引荐体系模型的战略流程:

  • 导入数据
  • 引荐用户点评较高的电影,咱们依据用户在前史记录中喜欢的电影来练习咱们的模型。咱们也能够依据用户不喜欢的电影来进一步改进引荐的准确性,但为了简略起见,本使命暂不考虑用户不喜欢的电影
  • 只保存观看过 5 部以上电影的用户
  • 为不同用户和电影分配不同 ID
  • 鉴于用户的偏好或许会跟着时刻而改变,因而咱们需求考虑用户的前史记录,其中前史记录中的不同事件具有与之相关的不同权重。因而,这是一个典型的时刻序列剖析问题,能够运用循环神经网络 (Recurrent neural networks, RNN) 来解决此问题
  • 预处理数据,以便能够将其传递到长短时记忆网络 (Long Short Term Memory, LSTM) :
    • 输入是用户前史观看的 5 部电影
    • 输出是用户观看的第 6 部电影
  • 构建模型履行以下操作:
    • 为输入影片创立嵌入
    • 将嵌入传递到 LSTM
    • LSTM 层的输出衔接到全衔接层
    • 在最终一层上运用 softmax 函数,以输出要引荐的电影列表

电影引荐体系

在本节中,咱们依据在上一末节中界说的模型战略完成电影引荐模型。

根据 LSTM 完成电影引荐体系

(1) 导入用户-电影数据集,该数据集包括用户列表,并且具有用户为不同电影供给的评分以及用户供给评分时相应的时刻戳:

import numpy as np
import pandas as pd
column_names = ['User', 'Movies', 'rating', 'timestamp']
ratings = pd.read_csv('u.data', sep='\t', names=column_names)
print(ratings.head())

数据集的示例如下所示:

   User  Movies  rating  timestamp
0   196     242       3  881250949
1   186     302       3  891717742
2    22     377       1  878887116
3   244      51       2  880606923
4   166     346       1  886397596

(2) 筛选出用户不喜欢的电影(即用户对电影评分较低)的数据样本或没有满足前史记录的用户数据样本。首要,扫除用户供给较低评分的电影数据样本:

ratings = ratings[ratings['rating']>3]
ratings = ratings.sort_values(by='timestamp')
ratings.reset_index(inplace=True)
ratings = ratings.drop(['index'],axis=1)

然后,咱们仅保存前史记录中点评的电影数量超越 5 的用户:

user_movie_count =ratings.groupby('User').agg({'Movies':'nunique'}).reset_index()
user_movie_count.columns = ['User','Movie_count']
ratings2 = ratings.merge(user_movie_count,on='User',how='inner')
movie_count = ratings2[ratings2['Movie_count']>5]
movie_count = movie_count.sort_values('timestamp')
movie_count.reset_index(inplace=True)
movie_count = movie_count.drop(['index'],axis=1)

(3) 为不同用户和电影分配不同 ID,以便后续运用:

ratings = movie_count
users = ratings.User.unique()
movies = ratings.Movies.unique()
userid2idx = {o:i for i,o in enumerate(users)}
moviesid2idx = {o:i for i,o in enumerate(movies)}
idx2userid = {i:o for i,o in enumerate(users)}
idx2moviesid = {i:o for i,o in enumerate(movies)}
ratings['Movies2'] = ratings.Movies.apply(lambda x: moviesid2idx[x])
ratings['User2'] = ratings.User.apply(lambda x: userid2idx[x])

(4) 预处理数据,运用巨细为 5滑动窗口构建输入电影,输出为用户已观看的第 6 部电影:

x = []
y = []
user_list = movie_count['User2'].unique()
for i in range(len(user_list)):
    total_user_movies = movie_count[movie_count['User2']==user_list[i]].copy()
    total_user_movies.reset_index(inplace=True)
    total_user_movies = total_user_movies.drop(['index'],axis=1)
    for j in range(total_user_movies.shape[0]-6):
        x.append(total_user_movies.loc[j:(j+4),'Movies2'].tolist())
        y.append(total_user_movies.loc[(j+5),'Movies2'].tolist())

(5) 预处理 xy 变量,以便能够将它们传递到模型,然后创立练习和测验数据集:

from keras.utils import to_categorical
l = list(moviesid2idx.keys())
print(len(l))
set([x for x in l if l.count(x) > 1])
y2 = to_categorical(y, num_classes = max(y)+1)
x_train = np.array(x[:40000])
x_test = np.array(x[40000:])
y_train = np.array(y2[:40000])
y_test = np.array(y2[40000:])

(6) 构建电影引荐模型:

model = Sequential()
model.add(Embedding(src_vocab, n_units, input_length=src_timesteps))
model.add((LSTM(100)))
model.add(Dense(1000,activation='relu'))
model.add(Dense(max(y)+1,activation='softmax'))
model.summary()

该模型的扼要信息输出如下:

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, 5, 32)             46304     
_________________________________________________________________
lstm (LSTM)                  (None, 100)               53200     
_________________________________________________________________
dense (Dense)                (None, 1024)              103424    
_________________________________________________________________
dense_1 (Dense)              (None, 1447)              1483175   
=================================================================
Total params: 1,686,103
Trainable params: 1,686,103
Non-trainable params: 0
_________________________________________________________________

(7) 编译并拟合模型构建完成的模型:

from keras.optimizers import Adam
adam = Adam(lr=0.0001)
model.compile(optimizer=adam, loss='categorical_crossentropy', metrics = ['acc'])
history = model.fit(x_train, y_train,
                epochs=20,
                batch_size=64,
                validation_data=(x_test, y_test),
                verbose=1)

(8) 对测验数据进行猜测:

pred = model.predict(x_test)

咱们假定,假如用户即将观看的第 6 部影片在引荐概率最高的前 12 部影片中,则表明该引荐体系能够向用户引荐适宜的影片,计算在所有测验用户中,引荐了适宜影片的比例:

count = 0
for i in range(x_test.shape[0]):
    rank = np.argmax(np.argsort(pred[i])[::-1]==np.argmax(y_test[i]))
    if rank<12:
        count+=1
print(count/x_test.shape[0])
# 0.1173

咱们所构建的电影引荐模型大约有 11.73% 的概率能够为用户引荐适宜的影片。