如何建立一个生产环境的推荐系统
优采云 发布时间: 2020-08-19 13:20如何建立一个生产环境的推荐系统
1.概述
前面介绍过哪些是推荐系统,以及推荐系统中的用例,比如基于用户的协同过滤来建立推荐系统。今天给你们介绍怎么完善一个生产环境的推荐系统。
2.内容
现在互联网上的内容好多,我们可能每晚还会接受来自不同消息。例如,电商网站、阅读博客、各类新闻文章等。但是,这些消息并不是所有的内容你都感兴趣,可能你只对技术博客感兴趣,或者个别新闻感兴趣等等。而如此内容怎么去满足用户的需求呢?我们须要一个精准的解决方案来简化用户的发觉过程。
2.1 推荐系统的作用是啥?
简而言之,推荐系统就是一个发觉用户喜好的系统。系统从数据中学习并向用户提供有效的建议。如果用户没有特意搜索某项物品,则系统会手动将该项带出。这样看起很神奇,比如,你在电商网站上浏览过某个品牌的衣服,当你在用一些社交软件、短视频软件、视频软件时,你会惊奇的发觉在你所使用的这种软件中,会给你推荐你刚才在电商网站上浏览的过的靴子。
其实,这得益于推荐系统的过滤功能。我们来瞧瞧一张简图,如下图所示:
从上图中,我们可以简单的总结出,整个数据流程如下:
2.2 依赖打算
我们使用Python来够完善推荐系统模型,需要依赖如下的Python依赖包:
pip install numpy
pip install scipy
pip install pandas
pip install jupyter
pip install requests
这里为简化Python的依赖环境,推荐使用Anaconda3。这上面集成了好多Python的依赖库,不用我们在额外去关注Python的环境打算。
接着,我们加载数据源,代码如下:
import pandas as pd
import numpy as np
df = pd.read_csv('resource/events.csv')
df.shape
print(df.head())
结果如下:
使用df.head()会复印数据前5行数据:
使用如下代码,查看风波类型有什么:
print(df.event.unique())
结果如下:
从上图可知,类型有三种,分别是:view、addtocart、transaction。
为了简化起见,以transaction类型为反例。代码如下所示:
trans = df[df['event'] == 'transaction']
trans.shape
print(trans.head())
结果如下图所示:
接着,我们来瞧瞧用户和物品的相关数据,代码如下:
visitors = trans['visitorid'].unique()
items = trans['itemid'].unique()
print(visitors.shape)
print(items.shape)
我们可以获得11719个去重用户和12025个去重物品。
构建一个简单而有效的推荐系统的经验法则是在不损失精准度的情况下降低数据的样本。这意味着,你只能为每位用户获取大概50个最新的事务样本,并且我们依然可以得到期望中的结果。
代码如下所示:
trans2 = trans.groupby(['visitorid']).head(50)
print(trans2.shape)
真实场景中,用户ID和物品ID是一个海量数字,人为很难记住,比如如下代码:
trans2['visitors'] = trans2['visitorid'].apply(lambda x : np.argwhere(visitors == x)[0][0])
trans2['items'] = trans2['itemid'].apply(lambda x : np.argwhere(items == x)[0][0])
print(trans2)
结果如下图所示:
2.3 构建矩阵2.3.1 构建用户-物品矩阵
从前面的代码执行的结果来看,目前样本数据中有11719个去重用户和12025个去重物品,因此,我们接下来建立一个稀疏矩阵。需要用到如下Python依赖:
from scipy.sparse import csr_matrix
实现代码如下所示:
occurences = csr_matrix((visitors.shape[0], items.shape[0]), dtype='int8')
def set_occurences(visitor, item):
occurences[visitor, item] += 1
trans2.apply(lambda row: set_occurences(row['visitors'], row['items']), axis=1)
print(occurences)
结果如下所示:
(0, 0) 1
(1, 1) 1
(1, 37) 1
(1, 72) 1
(1, 108) 1
(1, 130) 1
(1, 131) 1
(1, 132) 1
(1, 133) 1
(1, 162) 1
(1, 163) 1
(1, 164) 1
(2, 2) 1
(3, 3) 1
(3, 161) 1
(4, 4) 1
(4, 40) 1
(5, 5) 1
(5, 6) 1
(5, 18) 1
(5, 19) 1
(5, 54) 1
(5, 101) 1
(5, 111) 1
(5, 113) 1
: :
(11695, 383) 1
(11696, 12007) 1
(11696, 12021) 1
(11697, 12008) 1
(11698, 12011) 1
(11699, 1190) 1
(11700, 506) 1
(11701, 11936) 1
(11702, 10796) 1
(11703, 12013) 1
(11704, 12016) 1
(11705, 12017) 1
(11706, 674) 1
(11707, 3653) 1
(11708, 12018) 1
(11709, 12019) 1
(11710, 1330) 1
(11711, 4184) 1
(11712, 3595) 1
(11713, 12023) 1
(11714, 3693) 1
(11715, 5690) 1
(11716, 6280) 1
(11717, 3246) 1
(11718, 2419) 1
View Code
2.3.2 构建物品-物品共生矩阵
构建一个物品与物品矩阵,其中每位元素表示一个用户订购两个物品的次数,可以觉得是一个共生矩阵。要建立一个共生矩阵,需要将发生矩阵的转置与自身进行点乘。
cooc = occurences.transpose().dot(occurences)
cooc.setdiag(0)
print(cooc)
结果如下所示:
(0, 0) 0
(164, 1) 1
(163, 1) 1
(162, 1) 1
(133, 1) 1
(132, 1) 1
(131, 1) 1
(130, 1) 1
(108, 1) 1
(72, 1) 1
(37, 1) 1
(1, 1) 0
(2, 2) 0
(161, 3) 1
(3, 3) 0
(40, 4) 1
(4, 4) 0
(8228, 5) 1
(8197, 5) 1
(8041, 5) 1
(8019, 5) 1
(8014, 5) 1
(8009, 5) 1
(8008, 5) 1
(7985, 5) 1
: :
(11997, 12022) 1
(2891, 12022) 1
(12023, 12023) 0
(12024, 12024) 0
(11971, 12024) 1
(11880, 12024) 1
(10726, 12024) 1
(8694, 12024) 1
(4984, 12024) 1
(4770, 12024) 1
(4767, 12024) 1
(4765, 12024) 1
(4739, 12024) 1
(4720, 12024) 1
(4716, 12024) 1
(4715, 12024) 1
(4306, 12024) 1
(2630, 12024) 1
(2133, 12024) 1
(978, 12024) 1
(887, 12024) 1
(851, 12024) 1
(768, 12024) 1
(734, 12024) 1
(220, 12024) 1
View Code
这样一个稀疏矩阵就建立好了,并使用setdiag函数将对角线设置为0(即忽视第一项的值)。
接下来会用到一个和余弦相似度的算法类似的算法LLR(Log-Likelihood Ratio)。LLR算法的核心是剖析风波的计数,特别是风波同时发生的计数。而我们须要的技术通常包括:
表格表示如下:
事件A
事件B
事件B
A和B同时发生(K_11)
B发生,单A不发生(K_12)
任何风波但不收录B
A发生,但是B不发生(K_21)
A和B都不发生(K_22)
通过上述表格描述,我们可以较为简单的估算LLR的分数,公式如下所示:
LLR=2 sum(k)(H(k)-H(rowSums(k))-H(colSums(k)))
那回到本案例来,实现代码如下所示:
def xLogX(x):
return x * np.log(x) if x != 0 else 0.0
def entropy(x1, x2=0, x3=0, x4=0):
return xLogX(x1 + x2 + x3 + x4) - xLogX(x1) - xLogX(x2) - xLogX(x3) - xLogX(x4)
def LLR(k11, k12, k21, k22):
rowEntropy = entropy(k11 + k12, k21 + k22)
columnEntropy = entropy(k11 + k21, k12 + k22)
matrixEntropy = entropy(k11, k12, k21, k22)
if rowEntropy + columnEntropy 0:
actions_string = "\n".join(actions) + "\n"
actions = []
url = "http://127.0.0.1:9200/_bulk/"
headers = {
"Content-Type" : "application/x-ndjson"
}
requests.post(url, headers=headers, data=actions_string)
在浏览器中访问地址:9200/items2/_count,结果如下所示:
接下来,我们可以尝试将访问地址切换为这个:9200/items2/240708,结果如下所示:
3.总结
构建一个面向生产环境的推荐系统并不困难,目前现有的技术组件可以满足我们建立这样一个生产环境的推荐系统。比如Hadoop、Hive、HBase、Kafka、ElasticSearch等那些成熟的开源组件来建立我们的生产环境推荐系统。本案例的完整代码如下所示:
import pandas as pd
import numpy as np
from scipy.sparse import csr_matrix
import requests
import json
df = pd.read_csv('resource/events.csv')
# print(df.shape)
# print(df.head())
# print(df.event.unique())
trans = df[df['event'] == 'transaction']
# print(trans.shape)
# print(trans.head())
visitors = trans['visitorid'].unique()
items = trans['itemid'].unique()
# print(visitors.shape)
# print(items.shape)
trans2 = trans.groupby(['visitorid']).head(50)
# print(trans2.shape)
trans2['visitors'] = trans2['visitorid'].apply(lambda x : np.argwhere(visitors == x)[0][0])
trans2['items'] = trans2['itemid'].apply(lambda x : np.argwhere(items == x)[0][0])
# print(trans2)
occurences = csr_matrix((visitors.shape[0], items.shape[0]), dtype='int8')
def set_occurences(visitor, item):
occurences[visitor, item] += 1
trans2.apply(lambda row: set_occurences(row['visitors'], row['items']), axis=1)
# print(occurences)
cooc = occurences.transpose().dot(occurences)
cooc.setdiag(0)
# print(cooc)
def xLogX(x):
return x * np.log(x) if x != 0 else 0.0
def entropy(x1, x2=0, x3=0, x4=0):
return xLogX(x1 + x2 + x3 + x4) - xLogX(x1) - xLogX(x2) - xLogX(x3) - xLogX(x4)
def LLR(k11, k12, k21, k22):
rowEntropy = entropy(k11 + k12, k21 + k22)
columnEntropy = entropy(k11 + k21, k12 + k22)
matrixEntropy = entropy(k11, k12, k21, k22)
if rowEntropy + columnEntropy 0:
actions_string = "\n".join(actions) + "\n"
actions = []
url = "http://127.0.0.1:9200/_bulk/"
headers = {
"Content-Type" : "application/x-ndjson"
}
requests.post(url, headers=headers, data=actions_string)
View Code
4.结束语
这篇博客就和你们分享到这儿,如果你们在研究学习的过程当中有哪些问题,可以加群进行讨论或发送电邮给我,我会尽我所能为您解答,与君自勉!