推荐系统!基于tensorflow搭建混合神经网络精准推荐!

💡 作者:韩信子@ShowMeAI
📘 深度学习实战系列https://www.showmeai.tech/tutorials/42
📘 TensorFlow 实战系列https://www.showmeai.tech/tutorials/43
📘 本文地址https://www.showmeai.tech/article-detail/310
📢 声明:版权所有,转载请联系平台与作者并注明出处
📢 收藏ShowMeAI查看更多精彩内容

推荐系统是预测用户对多种产品的偏好的模型,互联网时代,它在各种领域大放异彩,从视频音乐多媒体推荐、到电商购物推荐、社交关系推荐,无处不在地提升用户体验。

最常用的推荐系统方法包括:基于产品特征(基于内容)、用户相似度(协同过滤等最近邻算法)、个人信息(基于知识)。当然,随着神经网络的日益普及,许多公司在业务中使用的推荐算法已经是上述方法的组合而成的混合推荐系统。

[En]

The most common recommendation system methods include: product feature-based (content-based), user similarity (collaborative filtering and other nearest neighbor algorithms), personal information (knowledge-based). Of course, with the increasing popularity of neural networks, the recommendation algorithms used in the business of many companies have been a hybrid recommendation system with the combination of all the above methods.

在本篇内容中,ShowMeAI 将给大家一一道来,从传统推荐系统算法到前沿的新式推荐系统,讲解原理并手把手教大家如何用代码实现。

本篇内容使用到的 🏆MovieLens 电影推荐数据集;,大家可以在 ShowMeAI 的百度网盘地址下载。

🏆 实战数据集下载(百度网盘):公众号『ShowMeAI研究中心』回复『 实战』,或者点击 这里 获取本文 [19]基于TensorFlow搭建混合神经网络推荐系统MovieLens 电影推荐数据集

ShowMeAI官方GitHubhttps://github.com/ShowMeAI-Hub

数据集包含观众对电影的评分结果。有不同大小的数据集。本文中的代码是通用的。您可以根据自己的计算资源选择合适的数据集。

[En]

The dataset contains the rating results of the movie by the audience. there are datasets of different sizes. The code in this article is universal. You can choose the appropriate dataset according to your own computing resources.

  • 小数据集为 600 名观众对 9000部电影的 10w 个打分,也包括电影标签特征。
  • 大数据集为 280000 名观众对 110w 部电影的 2700w 评分。

本文涉及的内容部分如下:

[En]

The content sections covered in this article are as follows:

  • 基本设置&数据预处理
  • 冷启动问题&处理
  • 基于内容的方法(tensorflow 和 numpy实现)
  • 传统协同过滤和神经协同过滤模型(tensorflow/keras 实现)
  • 混合模型模型(上下文感知,tensorflow/keras 实现)

; 💡 基本设置&数据预处理

📌 工具库导入

首先,我们导入所需的工具库:

[En]

First, we import the required tool libraries:


import pandas as pd
import numpy as np
import re
from datetime import datetime

import matplotlib.pyplot as plt
import seaborn as sns

from sklearn import metrics, preprocessing

from tensorflow.keras import models, layers, utils

📌 读取数据

接下来我们读取数据。

dtf_products = pd.read_csv("movie.csv")

movie电影文件中,每一行代表一部电影,右侧的两列包含其特征(标题与题材)。让我们读取用户数据:

dtf_users = pd.read_csv("ratings.csv").head(10000)

这个ratings表的每一行都是观众电影对,并显示观众对电影的评分(即 目标变量)。当然啦,并不是每个观众都看过所有的电影,所以我们可以给他们推荐没有看过的电影。这里的一种思路就是预估观众对于没有看过的电影的评分,再基于评分高低进行推荐。

📌 数据分析&特征工程

在实际挖掘和建模之前,我们首先做一些数据清理特征工程的工作,使数据更干净,更适合建模。

[En]

Before actual mining and modeling, we first do some work of * data cleaning * and * feature engineering * to make the data cleaner and suitable for modeling.

数据分析部分涉及的工具库,大家可以参考ShowMeAI制作的工具库速查表和教程进行学习和快速使用。
📘数据科学工具库速查表 | Pandas 速查表;
📘图解数据分析:从入门到精通系列教程


dtf_products = dtf_products[~dtf_products["genres"].isna()]
dtf_products["product"] = range(0,len(dtf_products))

dtf_products["name"] = dtf_products["title"].apply(lambda x: re.sub("[([].*?[)]]", "", x).strip())

dtf_products["date"] = dtf_products["title"].apply(lambda x: int(x.split("(")[-1].replace(")","").strip())
if "(" in x else np.nan)
dtf_products["date"] = dtf_products["date"].fillna(9999)

dtf_products["old"] = dtf_products["date"].apply(lambda x: 1 if x < 2000 else 0)

dtf_users["user"] = dtf_users["userId"].apply(lambda x: x-1)
dtf_users["timestamp"] = dtf_users["timestamp"].apply(lambda x: datetime.fromtimestamp(x))

dtf_users["daytime"] = dtf_users["timestamp"].apply(lambda x: 1 if 6<int(x.strftime("%H"))<20 else 0)

dtf_users["weekend"] = dtf_users["timestamp"].apply(lambda x: 1 if x.weekday() in [5,6] else 0)

dtf_users = dtf_users.merge(dtf_products[["movieId","product"]], how="left")
dtf_users = dtf_users.rename(columns={"rating":"y"})

dtf_products = dtf_products[["product","name","old","genres"]].set_index("product")
dtf_users = dtf_users[["user","product","daytime","weekend","y"]]

在上述过程中,有一些非常适合场景的特征工程和数据生成工作。例如,我们从时间戳生成了两个新字段:“是否为日光”和“是否为周末”。

[En]

In the above process, there are some feature engineering and data generation work that fits the scene very well. for example, we generate two new fields from the timestamp: “whether or not daylight” and “whether or not weekend”.

dtf_context = dtf_users[["user","product","daytime","weekend"]]

下一步我们构建 Moives-Features 矩阵:


tags = [i.split("|") for i in dtf_products["genres"].unique()]
columns = list(set([i for lst in tags for i in lst]))
columns.remove('(no genres listed)')

for col in columns:
    dtf_products[col] = dtf_products["genres"].apply(lambda x: 1 if col in x else 0)

我们得到的这个『电影-题材』矩阵是稀疏的(很好理解,一般一部电影只归属于有限的几个题材)。我们做一点可视化以更好地了解情况,代码如下:


fig, ax = plt.subplots(figsize=(20,5))
sns.heatmap(dtf_products==0, vmin=0, vmax=1, cbar=False, ax=ax).set_title("Products x Features")
plt.show()

下面是我们的 『观众/用户-电影』 评分矩阵,我们发现它更为稀疏(每位用户实际只看过几部电影,但总电影量很大)

tmp = dtf_users.copy()
dtf_users = tmp.pivot_table(index="user", columns="product", values="y")
missing_cols = list(set(dtf_products.index) - set(dtf_users.columns))
for col in missing_cols:
    dtf_users[col] = np.nan
dtf_users = dtf_users[sorted(dtf_users.columns)]

同样的热力图结果如下:

在特征工程部分,我们需要做一些典型的数据预处理,比如后面我们会用到神经网络模型,而这种计算模型,我们对数据做幅度缩放是非常必要的。

[En]

In the part of feature engineering, we need to do some typical data preprocessing, for example, we will use the neural network model later, and this computational model, we do amplitude scaling of the data is very necessary.

关于机器学习特征工程,大家可以参考 ShowMeAI 整理的特征工程最全解读教程。
📘机器学习实战 | 机器学习特征工程最全解读


dtf_users = pd.DataFrame(preprocessing.MinMaxScaler(feature_range=(0.5,1)).fit_transform(dtf_users.values),
columns=dtf_users.columns, index=dtf_users.index)

📌 数据切分

在对数据进行简单处理后,就像任何典型的机器学习任务一样,我们需要将数据划分为训练集测试集。如果我们结合上面的用户-电影矩阵,我们将进行类似于下图的垂直分割,这样训练集和测试集都将尽可能覆盖所有用户:

[En]

After simply processing the data, just like any typical machine learning task, we need to divide the data into * training set * and * test set * . If we combine the above “ * user-movie * ” matrix, we will do vertical segmentation similar to the following image, so that both the training set and the test set will cover all users as far as possible:


split = int(0.8*dtf_users.shape[1])
dtf_train = dtf_users.loc[:, :split-1]
dtf_test = dtf_users.loc[:, split:]

💡 冷启动问题&处理

📌 冷启动问题

想象一下,像《抖音》这样的应用,对于为新用户提供推荐(仅仅基于一些策略,比如热度排名等)并不是很准确,我们积累的用户信息也太少了。无法执行用户配置文件工作。这是任何推荐系统产品都会遇到的冷启动问题(即由于历史数据不足,系统无法建立用户与产品的关联)。

[En]

Imagine that an application like “Douyin” is not very accurate to provide recommendations for new users (only based on some strategies, such as hot ranking, etc.), and we accumulate too little information about users. User profile work can not be carried out. This is the * cold start problem * that any recommendation system product will encounter (that is, the system cannot establish any association between the user and the product because there is not enough historical data).

📌 冷启动处理方法

针对冷启动问题,有一些典型的处理方式,例如 基于知识的方法:在初次进入APP时询问用户的偏好,构建基本信息与知识,再基于知识进行推荐(比如不同『年龄段』和『性别』喜爱的媒体产品等)。

另外一种处理方法是 基于内容的方法。即基于产品的属性(比如我们当前的场景下,电影的题材、演员、主题等)进行匹配推荐。

💡 基于内容的推荐方法

📌 核心思想

我们来介绍一下 基于内容的方法

这个方法是基于产品属性进行关联和推荐的,例如,如果『用户A喜欢产品1』,并且『产品2与产品1从属性上看相似』,那么『用户A可能也会喜欢产品2』。简单地说,这个想法是『 用户实际上对产品的功能/属性而不是产品本身进行评分』。

换句话说,如果我喜欢与音乐和艺术相关的产品,那是因为我喜欢那些功能/属性(音乐和艺术)。我们可以根据这些信息提出建议。

[En]

In other words, if I like products related to music and art, it’s because I like those features / attributes (music and art). We can make recommendations based on this information.

; 📌 代码实现

我们从数据中随机选择了一个“查看者/用户”作为我们的新用户的例子,他现在已经使用了足够的产品来创建训练和测试向量。

[En]

We randomly selected a “viewer / user” from the data as an example of our new user, who has now used enough products to create training and test vectors.


i = 1
train = dtf_train.iloc[i].to_frame(name="y")
test = dtf_test.iloc[i].to_frame(name="y")

tmp = test.copy()
tmp["y"] = np.nan
train = train.append(tmp)

下面我们估测『观众/用户』对每个特征的权重,回到我们前面整理完的 User-Products 矩阵和 Products-Features 矩阵。


usr = train[["y"]].fillna(0).values.T
prd = dtf_products.drop(["name","genres"],axis=1).values
print("Users", usr.shape, " x  Products", prd.shape)

我们把这 2 个矩阵相乘,我们获得了一个『 用户-特征』矩阵,它包含这个用户对每个特征的估计权重。我们进而把这些权重应重新应用于『 产品-特征』矩阵就可以获得测试集结果。


usr_ft = np.dot(usr, prd)

weights = usr_ft / usr_ft.sum()

pred = np.dot(weights, prd.T)

test = test.merge(pd.DataFrame(pred[0], columns=["yhat"]), how="left", left_index=True, right_index=True).reset_index()
test = test[~test["y"].isna()]
test

上面是一个非常非常简单的思路,我们用 numpy 对它进行了实现。其实这个过程也可以在原始数据张量上进行:


import tensorflow as tf

usr_ft = tf.matmul(usr, prd)

weights = usr_ft / tf.reduce_sum(usr_ft, axis=1, keepdims=True)

pred = tf.matmul(weights, prd.T)

仅仅完成预估步骤还不够,我们需要对预测推荐进行有效 评估,怎么做呢,在当前这个推荐场景下,我们可以使用 准确性平均倒数排名(MRR,一种针对排序效果的统计度量)。


def mean_reciprocal_rank(y_test, predicted):
    score = []
    for product in y_test:
        mrr = 1 / (list(predicted).index(product) + 1) if product
        in predicted else 0
        score.append(mrr)
    return np.mean(score)

有时候,在全部排序结果列表上评估,效果一般且计算量太大,我们可以选择标准答案的 top k 进行评估(下面代码中 k 取值为 5)。

print("--- user", i, "---")

top = 5
y_test = test.sort_values("y", ascending=False)["product"].values[:top]
print("y_test:", y_test)

predicted = test.sort_values("yhat", ascending=False)["product"].values[:top]
print("predicted:", predicted)

true_positive = len(list(set(y_test) & set(predicted)))
print("true positive:", true_positive, "("+str(round(true_positive/top*100,1))+"%)")
print("accuracy:", str(round(metrics.accuracy_score(y_test,predicted)*100,1))+"%")
print("mrr:", mean_reciprocal_rank(y_test, predicted))

上图显示在 user1 上,我们预估结果和 top5 真实结果,有 4 个结果是重叠的。(不过因为我们预估结果的序并不完全和标准答案一样,所以指标上看 accuracy 和 mrr 会低一点)


test.merge(
       dtf_products[["name","old","genres"]], left_on="product",
       right_index=True
).sort_values("yhat", ascending=False)

💡 协同过滤推荐算法

📌 核心思想

协同过滤是一类典型的『近邻』推荐算法,基于用户和用户的相似性,或者产品和产品的相似性来构建推荐。比如 user-based collaborative filtering(基于用户的协同过滤)中,我们认为『用户A喜欢产品1』,而基于 用户行为计算判定『用户B和用户A相似』,那么『用户B可能也会喜欢产品1』。

注意到协同过滤算法中,很重要的步骤是我们需要基于用户历史的行为来构建相似度度量(user-user 或 item-item 相似度)。

与上面提到的基于内容的推荐算法不同,协同过滤不需要产品属性来建模,而是基于大量用户的历史行为来计算和构建相似的度量标准(例如,在这种情况下,我们可以基于不同观众历史中的一批电影的得分相似度来构建)。

[En]

Unlike the content-based recommendation algorithms mentioned above, collaborative filtering does not need product attributes to model, but rather calculates and builds similar metrics based on the historical behavior of a large number of users (for example, in this case, we can build based on the score similarity on a batch of movies in different audience history).

; 📌 基础协同过滤算法

协同过滤是『基于用户行为』的推荐算法,我们会『通过群体的行为来找到某种相似性』(用户之间的相似性或者物品之间的相似性),通过相似性来为用户做决策和推荐。协同过滤细分一下,有以下基于邻域的、基于隐语义模型2大类方法。

基于近邻的协同过滤

基于近邻的协同过滤包含 user-based cf(基于用户的协同过滤)和 item-based cf(基于物品的协同过滤)两种方式,核心思想如下图所示:

核心步骤为以下3步:

① 根据历史数据收集用户偏好(比如本例中的打分,比如)。

② 找到相似的用户(基于用户)或物品(基于物品)。

③ 基于相似性计算和推荐。

其中的 similarity 相似度计算部分,可以基于一些度量准则来完成,比如最常用到的相似度度量是余弦相似度:

cosine similarity = S C ( A , B ) : = cos ⁡ ( θ ) = A ⋅ B ∥ A ∥ ∥ B ∥ = ∑ i = 1 n A i B i ∑ i = 1 n A i 2 ∑ i = 1 n B i 2 \text{cosine similarity}=S_{C}(A, B):=\cos (\theta)=\frac{A \cdot \mathbf{B}}{\|\mathbf{A}\|\|\mathbf{B}\|}=\frac{\sum_{i=1}^{n} A_{i} B_{i}}{\sqrt{\sum_{i=1}^{n} A_{i}^{2} \sqrt{\sum_{i=1}^{n} B_{i}^{2}}}}cosine similarity =S C ​(A ,B ):=cos (θ)=∥A ∥∥B ∥A ⋅B ​=∑i =1 n ​A i 2 ​∑i =1 n ​B i 2 ​​​∑i =1 n ​A i ​B i ​​

在本例中A和B可以是两个用户的共同电影对应的打分向量,或者两部电影的共同打分用户的打分向量,也就是打分矩阵中的两行或者两列。

当然,我们也可以基于聚类等方法找到相似的用户和项目。

[En]

Of course, we can also find similar users and items based on clustering and other methods.

; 基于隐语义模型的协同过滤

协作过滤的另一个实现是基于矩阵分解的,在这种情况下,矩阵分解可用于预测用户对产品的评价。矩阵分解方法将大的“用户-项目”得分矩阵分解为两个较小的因素矩阵,即“用户-因素”矩阵和“产品-因素”矩阵。然后根据这两个矩阵对未评分的“用户-项目”对进行评分。

[En]

Another implementation of collaborative filtering is based on matrix decomposition, which in this case can be used to predict the user’s evaluation of a product. The matrix decomposition method divides the large “user-item” score matrix into two smaller factor matrices, namely the “user-factor” matrix and the “product-factor” matrix. Then score the unscored “user-item” pairs based on these two matrices.

具体来说,每个因素可能代表了某一属性维度的程度,例如,如果我们确定了年龄和主题娱乐这两个属性,那么我们可以根据评分矩阵对这两个维度进行分解。

[En]

Specifically, each factor may represent the degree of a certain attribute dimension, for example, if we determine the two attributes “age” and “theme entertainment”, then we can decompose these two dimensions based on the scoring matrix.

代码实现

在 Python 中,要实现上述提到的2类协同过滤算法,最方便的工具库之一是 📘scikit-surprise(从名字大家可以看出,它借助了 scikit-learn 的一些底层算法来实现上层的协同过滤)。它包含了上述提到的基于近邻的协同过滤和基于隐语义模型的协同过滤。

不过矩阵实现方法也是各种深度学习模型所擅长的,我们在这里使用tensorflow/keras来做一点实现。

我们先准备好『用户-物品』数据(本例中的用户是观众,物品是电影):

train = dtf_train.stack(dropna=True).reset_index().rename(columns={0:"y"})
train.head()

我们会利用神经网络的 嵌入层来创建『用户-因子』和『产品-因子』矩阵,这里特别适合用神经网络的 embedding 层来完成映射矩阵构建,我们为用户和产品分别构建 embedding 矩阵。Embedding 矩阵的维度就是我们这个地方设定的因子的个数。下面我们使用 tensorflow 来完成这个过程。

embeddings_size = 50
usr, prd = dtf_users.shape[0], dtf_users.shape[1]

xusers_in = layers.Input(name="xusers_in", shape=(1,))
xusers_emb = layers.Embedding(name="xusers_emb", input_dim=usr, output_dim=embeddings_size)(xusers_in)
xusers = layers.Reshape(name='xusers', target_shape=(embeddings_size,))(xusers_emb)

xproducts_in = layers.Input(name="xproducts_in", shape=(1,))
xproducts_emb = layers.Embedding(name="xproducts_emb", input_dim=prd, output_dim=embeddings_size)(xproducts_in)
xproducts = layers.Reshape(name='xproducts', target_shape=(embeddings_size,))(xproducts_emb)

xx = layers.Dot(name='xx', normalize=True, axes=1)([xusers, xproducts])

y_out = layers.Dense(name="y_out", units=1, activation='linear')(xx)

model = models.Model(inputs=[xusers_in,xproducts_in], outputs=y_out, name="CollaborativeFiltering")
model.compile(optimizer='adam', loss='mean_absolute_error', metrics=['mean_absolute_percentage_error'])

在这种情况下,因为我们最终预测电影的得分,所以我们使用模型来解决这个问题作为回归问题,我们将使用平均绝对误差作为最终的损失函数。当然,当我们实际解决推荐问题时,可能不需要得到一个准确的分数,而是希望根据这些分数完成一个排名和最终的推荐。

[En]

In this case, because we ultimately predict the score of the movie, we use the model to solve this problem as a regression problem, and we will use the average absolute error as the final loss function. Of course, when we actually solve the problem of recommendation, we may not need to get an accurate score, but hope to complete a ranking and final recommendation based on these scores.

为了便于查看,让我们打印模型的示意图和中间层的尺寸,如下所示

[En]

Let’s print the schematic diagram of the model and the dimensions of the middle tier for easy viewing, as follows

utils.plot_model(model, to_file='model.png', show_shapes=True, show_layer_names=True)

然后我们可以在我们的数据上训练、评估和测试我们的模型。

[En]

Then we can train, evaluate and test our model on our data.


training = model.fit(x=[train["user"], train["product"]], y=train["y"], epochs=100, batch_size=128, shuffle=True, verbose=0, validation_split=0.3)

model = training.model

test["yhat"] = model.predict([test["user"], test["product"]])
test

在这个模型的最终估计上,你可以看到该模型已经能够为以前从未见过的新电影打分。我们可以根据这个分数对最终推荐进行排序和完成。以我们的第一个用户为例,我们可以看到,他是根据预测得分进行推荐的,评估结果如下。

[En]

On the final estimate of this model, you can see that the model has been able to score predictions for new movies that have never been seen before. We can sort and complete the final recommendation based on this score. Taking our first user as an example, we can see that he is recommended based on the prediction score, and the evaluation results are as follows.

📌 神经协同过滤算法

模型介绍

大家在前面看到的协同过滤模型,学习能力相对比较弱,对于我们的信息做的是初步的挖掘,而现代的很多新的推荐系统实际上都使用了深度学习。也可以把深度学习和协同过滤结合,例如 Neural Collaborative Filtering (2017) 结合了来自神经网络的非线性和矩阵分解。该模型旨在充分利用嵌入空间,不仅将其用于传统的协同过滤,还用于完全连接的深度神经网络,新添加的模型组成部分会捕获矩阵分解可能遗漏的模式和特征,如下图所示:

; 代码实现

让我们实现此模型的一个简单版本:

[En]

Let’s implement a simple version of this model:


embeddings_size = 50
usr, prd = dtf_users.shape[0], dtf_users.shape[1]

xusers_in = layers.Input(name="xusers_in", shape=(1,))
xproducts_in = layers.Input(name="xproducts_in", shape=(1,))

cf_xusers_emb = layers.Embedding(name="cf_xusers_emb", input_dim=usr, output_dim=embeddings_size)(xusers_in)
cf_xusers = layers.Reshape(name='cf_xusers', target_shape=(embeddings_size,))(cf_xusers_emb)

cf_xproducts_emb = layers.Embedding(name="cf_xproducts_emb", input_dim=prd, output_dim=embeddings_size)(xproducts_in)
cf_xproducts = layers.Reshape(name='cf_xproducts', target_shape=(embeddings_size,))(cf_xproducts_emb)

cf_xx = layers.Dot(name='cf_xx', normalize=True, axes=1)([cf_xusers, cf_xproducts])

nn_xusers_emb = layers.Embedding(name="nn_xusers_emb", input_dim=usr, output_dim=embeddings_size)(xusers_in)
nn_xusers = layers.Reshape(name='nn_xusers', target_shape=(embeddings_size,))(nn_xusers_emb)

nn_xproducts_emb = layers.Embedding(name="nn_xproducts_emb", input_dim=prd, output_dim=embeddings_size)(xproducts_in)
nn_xproducts = layers.Reshape(name='nn_xproducts', target_shape=(embeddings_size,))(nn_xproducts_emb)

nn_xx = layers.Concatenate()([nn_xusers, nn_xproducts])
nn_xx = layers.Dense(name="nn_xx", units=int(embeddings_size/2), activation='relu')(nn_xx)

y_out = layers.Concatenate()([cf_xx, nn_xx])
y_out = layers.Dense(name="y_out", units=1, activation='linear')(y_out)

model = models.Model(inputs=[xusers_in,xproducts_in], outputs=y_out, name="Neural_CollaborativeFiltering")
model.compile(optimizer='adam', loss='mean_absolute_error', metrics=['mean_absolute_percentage_error'])

我们还可以绘制模型的结构,如下所示。

[En]

We can also draw the structure of the model, as shown below.

utils.plot_model(model, to_file='model.png', show_shapes=True, show_layer_names=True)

基于目前的神经网络模型,我们预测我们最终的电影评分,并根据预测的评分对其进行排名和推荐,评估结果如下所示。

[En]

Based on the current neural network model, we predict our final movie score, and rank and recommend it according to the predicted score, and the results of the evaluation are shown below.

💡 混合网络模型

📌 模型介绍

我们展示了如何结合我们用户和产品(当前场景中电影推荐的场景)的评分数据,构建协同过滤算法和基本神经网络算法,完成对最终评分的预测和推荐。但事实上,我们的数据中有更多的信息。

[En]

We showed how to combine the scoring data of our users and products (the scene recommended by the movie in the current scene) to build a collaborative filtering algorithm and a basic neural network algorithm to complete the prediction and recommendation of the final score. but in fact, there is more information in our data.

  • 用户行为 当前场景下是电影的打分,它是一种显式用户反馈;有些场景下我们会使用隐式的用户反馈,比如说用户的点击或者深度浏览和完播等行为。
  • 产品信息 产品的标签和描述(这里的电影题材、标题等),主要用于基于内容的方法。
  • 用户信息 人口统计学信息(即性别和年龄)或行为(即偏好、屏幕上的平均时间、最频繁的使用时间),主要用于基于知识的推荐。
  • 上下文 关于评分情况的附加信息(如何时、何地、搜索历史),通常也包含在基于知识的推荐中。

现代推荐系统为了更精准的给大家进行推荐,会尽量的结合所有我们能够收集到的信息。大家日常使用的抖音或者B站,它们在给大家推荐视频类的内容的时候,会更加全面的使用我们上面提及到的所有的信息,甚至包含APP能采集到的更丰富的信息。

📌 代码实现

结合这个例子,我们还将这些更丰富的信息(主要是上下文信息)结合到网络中,构建一个混合模型,以完成更准确的估计和建议。

[En]

Combined with this example, we also combine these richer information (mainly context information) into the network to build a hybrid model to complete more accurate estimates and recommendations.


features = dtf_products.drop(["genres","name"], axis=1).columns
print(features)

context = dtf_context.drop(["user","product"], axis=1).columns
print(context)

基本功能和上下文功能如下

[En]

The basic and contextual features are as follows

接下来,让我们将这些附加信息添加到训练集中:

[En]

Next, let’s add this additional information to the * training set * :

train = dtf_train.stack(dropna=True).reset_index().rename(columns={0:"y"})

train = train.merge(dtf_products[features], how="left", left_on="product", right_index=True)

train = train.merge(dtf_context, how="left")

注意我们这里并没有对测试集直接去执行相同的操作,因为实际的生产环境当中,我们可能没有办法提前的去获知一些上下文的信息,所以我们会为上下文的信息去插入一个静态的值去做填充。
当然我们在实际预估的时候,是可以比较准确的去做填充的。比如我们在星期一晚上为我们平台的用户进行预测,则上下文变量应为 daytime=0week=0

下面我们来构建 上下文感知混合模型,神经网络的结构非常灵活,我们可以在网络中添加任何我们想要补充的信息,我们把上下文等额外信息也通过网络组件的形式补充到神经协同过滤网络结构中,如下所示。

这一过程相当于在以前的神经协同过滤模型的基础上增加了一些新的组块。下面的实现代码看起来很长,但实际上它只是在前面的实现中添加了一些行:

[En]

This process is equivalent to adding some new chunks on the basis of the previous neural collaborative filtering model. The following implementation code looks huge, but in fact it just adds some lines to the previous implementation:

embeddings_size = 50
usr, prd = dtf_users.shape[0], dtf_users.shape[1]
feat = len(features)
ctx = len(context)

xusers_in = layers.Input(name="xusers_in", shape=(1,))
xproducts_in = layers.Input(name="xproducts_in", shape=(1,))

cf_xusers_emb = layers.Embedding(name="cf_xusers_emb", input_dim=usr, output_dim=embeddings_size)(xusers_in)
cf_xusers = layers.Reshape(name='cf_xusers', target_shape=(embeddings_size,))(cf_xusers_emb)

cf_xproducts_emb = layers.Embedding(name="cf_xproducts_emb", input_dim=prd, output_dim=embeddings_size)(xproducts_in)
cf_xproducts = layers.Reshape(name='cf_xproducts', target_shape=(embeddings_size,))(cf_xproducts_emb)

cf_xx = layers.Dot(name='cf_xx', normalize=True, axes=1)([cf_xusers, cf_xproducts])

nn_xusers_emb = layers.Embedding(name="nn_xusers_emb", input_dim=usr, output_dim=embeddings_size)(xusers_in)
nn_xusers = layers.Reshape(name='nn_xusers', target_shape=(embeddings_size,))(nn_xusers_emb)

nn_xproducts_emb = layers.Embedding(name="nn_xproducts_emb", input_dim=prd, output_dim=embeddings_size)(xproducts_in)
nn_xproducts = layers.Reshape(name='nn_xproducts', target_shape=(embeddings_size,))(nn_xproducts_emb)

nn_xx = layers.Concatenate()([nn_xusers, nn_xproducts])
nn_xx = layers.Dense(name="nn_xx", units=int(embeddings_size/2), activation='relu')(nn_xx)

features_in = layers.Input(name="features_in", shape=(feat,))
features_x = layers.Dense(name="features_x", units=feat, activation='relu')(features_in)

contexts_in = layers.Input(name="contexts_in", shape=(ctx,))
context_x = layers.Dense(name="context_x", units=ctx, activation='relu')(contexts_in)

y_out = layers.Concatenate()([cf_xx, nn_xx, features_x, context_x])
y_out = layers.Dense(name="y_out", units=1, activation='linear')(y_out)

model = models.Model(inputs=[xusers_in,xproducts_in, features_in, contexts_in], outputs=y_out, name="Hybrid_Model")
model.compile(optimizer='adam', loss='mean_absolute_error', metrics=['mean_absolute_percentage_error'])

让我们还画出整个模型的结构。

[En]

Let’s also draw the structure of the whole model.

utils.plot_model(model, to_file='model.png', show_shapes=True, show_layer_names=True)

混合模型有更多的输入数据源,我们需要在实际培训期间将所有这些数据都输入到模型中:

[En]

The hybrid model has more input data sources, and we need to feed all these data into the model during the actual training:


training = model.fit(x=[train["user"], train["product"], train[features], train[context]], y=train["y"],
                     epochs=100, batch_size=128, shuffle=True, verbose=0, validation_split=0.3)
model = training.model

test["yhat"] = model.predict([test["user"], test["product"], test[features], test[context]])

最后,基于混合模型的预测得分进行推荐,评价指标如下:

[En]

Finally, the recommendation is based on the prediction score of the hybrid model, and the evaluation indicators are as follows:

我们单独看 user1 这个用户,混合模型在多种信息的支撑下,获得了最高的准确度。

💡 结论

本文介绍了推荐系统的基本知识和推荐系统的不同构建方法。我们实现并改进了各种方法,包括基于内容的推荐实现和基于协同过滤的推荐实现。我们将更丰富的产品信息和上下文信息添加到网络中,以实现混合网络模型。您可以参考实施流程并将其应用于您自己的场景。

[En]

This paper explains the basic knowledge of recommendation system and different construction methods of recommendation system. We implement and improve various methods, including content-based recommendation implementation and collaborative filtering-based recommendation implementation. We add richer product information and context information to the network to implement a hybrid network model. You can refer to the implementation process and apply it to your own scenarios.

参考资料

推荐系统!基于tensorflow搭建混合神经网络精准推荐!

Original: https://blog.csdn.net/ShowMeAI/article/details/126296273
Author: ShowMeAI
Title: 推荐系统!基于tensorflow搭建混合神经网络精准推荐!

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/496600/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球