暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

零基础入门推荐系统:四种内容召回逻辑

Coggle数据科学 2022-12-12
310

在最近举办的零基础入门推荐系统中,我们在召回部分布置了多个召回算法的任务,在本文我们也将介绍这些实现的逻辑:

  • 基于用户相似的召回逻辑
  • 基于文章相似的召回逻辑
  • 基于文章内容相似的召回逻辑
  • 基于文章热度的召回逻辑

步骤1:用户文章打分矩阵

不管在进行用户相似还是文章相似的计算过程中,都需要构建用户与文章的打分矩阵,然后借助这个矩阵计算用户与用户、文章与文章的相似度。

可以使用交叉表来统计评分矩阵,计算逻辑如下(如果用户对文章阅读次数越多,则认为评分越高):

pd.crosstab(
  [1, 1, 2, 2, 3, 3], 
  [4, 5, 4, 4, 5, 6]
)

但使用交叉表会直接导致内存爆炸,本次比赛中我们需要构建一个维度为250000 * 35380维度的矩阵,直接构造会导致内存爆炸。

一种替代方法是使用稀疏矩阵,稀疏矩阵可以使用更少的内存来存储稀疏的数值。具体代码参考如下:

from scipy.sparse import lil_matrix

user_atricle_matrix = lil_matrix((250000, 35380), dtype=np.uint8)
user_atricle_matrix[
    train_user_article_count['user_id'].values[:], 
    train_user_article_count['click_article_id_encode'].values[:]
] = train_user_article_count['click_timestamp'].values[:]

这里我们选择使用Row-based list of lists sparse matrix(基于行的列表列表稀疏矩阵),其支持支持加法、减法、乘法、除法和矩阵幂。

当然你也可以选择其他的稀疏矩阵格式,这里稀疏矩阵的优缺点对比我们后续展开讲解。

用户与文章打分矩阵中,使用稀疏矩阵的格式有两个优点:

  • 对内存友好,只需要额外的200M内存
  • 对性能友好,稀疏矩阵的内积运算比稠密句子的内积运算更快

步骤2:用户相似召回

在计算得到用户与文章的评分矩阵后,接下来我们就可以直接使用矩阵去计算用户与用户之间的相似度。注意这里的每一行是一个用户对所有文章的评分:

# 对评分矩阵进行归一化
from sklearn.preprocessing import normalize
user_atricle_matrix = normalize(user_atricle_matrix, norm='l2')

# 计算用户与用户之间的相似度
user2user_distance = []
for idx in range(len(val_user_idx) // 10000):
    user2user_distance.append(
        user_atricle_matrix[val_user_idx[idx*10000:(idx+1)*10000]].dot(user_atricle_matrix.T)
    )

接下来我们需要按照用户的相似度得到待选文章的列表,具体的逻辑如下:使用用户相似度找到每个用户阅读过的文章,然后将文章进行评分排序。

top_n = 25
for user_id, distance in zip(val_user_idx[:10], user2user_distance):
    distance = distance.toarray()[0]
    ids = distance.argsort()[::-1]
    
    # 待选相似用户
    similar_user_id = ids[1:top_n+1]
    similar_user_distance = distance[ids[1:top_n+1]]
    similar_user_distance = lil_matrix(similar_user_distance)
    
    # 计算得到待选文章的评分
    similar_doc_distance = similar_user_distance.dot(user_atricle_matrix[similar_user_id])
    similar_doc_top50 = similar_doc_distance.toarray()[0].argsort()[::-1][:50]
    similar_doc_top50 = [x for x in similar_doc_top50 if x not in train_history_doc[user_id]][:50]
    
    print(user_id, mrr(val_label[user_id], similar_doc_top50))

步骤3:文章相似召回

文章相似召回的逻辑与用户相似召回的逻辑相同,首先也需要有用户与文章的评分矩阵,然后需要取计算文章与文章之间的相似度。

# 计算文章与文章之间的相似度
doc2doc_distance = []
for idx in range(len(article_lbl.classes_) // 10000 + 1):
    doc2doc_distance.append(
        user_atricle_matrix.T.dot(user_atricle_matrix[:, idx*10000:(idx+1)*10000])
    )

接下来使用文章相似结果可以直接得到待选的文章:

top_n = 25
val_mrr = []
for row in train_clicks.loc[train_clicks_val_idx].iloc[:1000].itertuples():
    user_id = row.user_id
    distance = doc2doc_distance[train_history_doc.loc[user_id]].sum(0)
    distance = np.array(distance)[0]
    similar_doc_top = distance.argsort()[::-1][1:]
    similar_doc_top = [x for x in similar_doc_top if x not in train_history_doc.loc[user_id]][:top_n]

步骤4:文章内容召回

文章内容相似可以从文章的嵌入矩阵来进行计算,计算完成后继续文章相似度的召回。文章嵌入矩阵的相似度计算代码如下:

doc2doc_content_distance = []
for idx in range(len(article_lbl.classes_) // 100 + 1):
    doc2doc_content_distance.append(
        articles_emb_selected.dot(articles_emb_selected[idx*100:(idx+1)*100].T)
    )
    
    break

但上述计算代码速度会非常慢,因为文章嵌入句子是一个稠密矩阵,在计算内积时速度很慢很慢。

可以考虑如下相似度加速逻辑:

  • 先聚类,在同一类别中进行相似度
  • 使用近似搜索逻辑,如HNSW

步骤5:文章热度召回

文章热度可以理解为排行榜,其可以代表文章在一段时间内的流行程度。按照新闻平台的内容分发逻辑,热门文章曝光量更大。

首先计算得到文章发部时间,计算得到小时和天:

train_clicks['click_ts_hour'] = train_clicks['click_timestamp'] // 3600
train_clicks['click_ts_day'] = train_clicks['click_timestamp'] // 86400

train_clicks['click_ts_hour'] = train_clicks['click_ts_hour'].astype(int)
train_clicks['click_ts_day'] = train_clicks['click_ts_day'].astype(int)

计算发布小时&天内,文章的阅读次数,然后将热门的文章推荐给用户:

article_day_hot = train_clicks.loc[train_clicks_train_idx].groupby('click_ts_day')['click_article_id_encode'].value_counts()
article_hour_hot = train_clicks.loc[train_clicks_train_idx].groupby('click_ts_hour')['click_article_id_encode'].value_counts()

思考与总结

在本文我们尝试了多种内容召回逻辑,但每种逻辑得到的效果其实存在交叉区别。按照计算基于文章相似度召回和热度召回的逻辑效果最好。

后续同学们也可以参考如下思路进行进一步尝试:使用上述方法进行综合打分,比如每个思路得到的文章权重为0.25,得到综合的文章排序。

本文代码资料:https://coggle.club/blog/30days-of-ml-202212

本文比赛链接:https://tianchi.aliyun.com/competition/entrance/531842/information

 竞赛交流群 邀请函  #

△长按添加竞赛小助手
每天Kaggle算法竞赛、干货资讯汇总

与 28000+来自竞赛爱好者一起交流~

文章转载自Coggle数据科学,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论