当前位置: 首页 > 科技观察

3亿会员,4亿商品,深度学习在大型电商商品推荐中的应用实践!

时间:2023-03-11 23:49:33 科技观察

在电子商务行业,为用户推荐产品一直是一个非常热门和重要的话题。成熟的方法有很多,但各有优缺点。常见算法电子产品推荐中常见的算法大致如下:基于食品A和食品B等产品的相似度,根据它们的价格、口味、保质期、品牌等维度,可以计算出它们的相似度。可想而知,我买了包子,很有可能一路带上一盒饺子回家。优点:冷启动,只要有产品数据,在业务前期用户数据不多的时候也可以做推荐。缺点:预处理复杂。任何产品至少可以有数百个维度。如何选择合适的尺寸进行计算涉及到工程经验,这是用钱买不来的。典型:亚马逊的早期推荐系统。基于关联规则的最常见的方法是通过用户的购买习惯。最经典的案例就是“啤酒尿布”案例,但这种方式在实际操作中很少用到。首先,我们需要制定关联规则。数据量一定要足够,否则置信度太低。当数据量增加时,我们有更多优秀的方法。可以说是毫无亮点。业界的算法有apriori、ftgrow等。优点:操作简单易用,上手速度快,部署非常方便。缺点:需要的数据较多,精度效果一般。典型:早期运营商的套餐推荐。基于物品的协同推荐假设物品A已经被小张、小明、小东购买过;B项已被小红、小李、小陈购买;C项已被小张、小明和小李购买。直观上,物品A和物品C的购买者具有更高的相似度(与物品B相比)。现在我们可以向小东推荐C项,向小李推荐A项。这个推荐算法比较成熟,用的公司也比较多。优点:比较准确,结果可解释性强,副产品可以按产品热度排名。缺点:计算复杂,数据存储存在瓶颈,对冷门商品推荐效果差。典型:早期一号店的产品推荐。基于用户的协同推荐假设用户A购买了可乐、雪碧、火锅底料;用户B购买了卫生纸、衣服和鞋子;用户C购买了火锅、果汁、七喜。直观上,用户A和用户C更相似(与用户B相比)。现在我们可以把用户C买过的其他东西推荐给用户A,把用户A买过的其他东西推荐给用户C,优缺点和用户C类似,item-based协同推荐类似,不再赘述.基于模型的推荐svd+、特征值分解等,将用户的购买行为矩阵拆分为两组权重矩阵的乘积,一组矩阵代表用户的行为特征,一组矩阵代表产品的重要性。在此过程中,计算每个产品在历史训练矩阵下的可能性,供用户推荐。优点:准确,对于冷门商品有很好的推荐效果。缺点:计算量非常大,矩阵分裂的性能和容量瓶颈始终受到约束。典型:惠普电脑推荐。基于时间序列的推荐比较特别。在电子商务中很少用到,但在推特、脸书、豆瓣上用得比较多。就是在只有赞同和不赞成的情况下如何对评论进行排序。基于深度学习的推荐现在比较流行的有CNN(卷积神经网络)、RNN(递归神经网络)、DNN(深度神经网络),上面的推荐例子中都用到了,但是还处于实验阶段.有一种基于word2vec的方法比较成熟,也是我们今天介绍的重点。优点:推荐效果非常准确,对基础存储资源占用少。缺点:工程应用不成熟,模型训练和调参技巧较难。典型:苏宁易购会员产品推荐。引入item2vec项目。现在苏宁拥有约4亿种产品,10000多个产品类别,近40个大品类。如果通过传统的协同推荐进行实时计算,服务器成本和计算能力是非常大的限制。由于会员研发部门不是主要推荐的应用部门,所以在选型上我们期待更高效、高速、相对准确的简化版模型。因此,我们在word2vec原有算法的基础上,模仿了itemNvec的方法。首先我们从理论上拆分itemNvec:01.partone:目标产品前后的n-gram目标产品对目标产品的影响程度。这是两个用户userA和userB在e-buy上的消费时间线,灰色框里面是我们的观察对象。请问一下,如果我们改变灰框内userA和userB的购买项目,直观的可能性有多大?直觉经验告诉我们,这是不可能的,或者说绝对不常见。因此,我们有一个初步假设,对于特定品类中的某些用户,用户的消费行为是持续受到影响的。换句话说,我买什么取决于我以前买过什么。如何通过算法语言来解释上述事情?让我们回忆一下,朴素贝叶斯是如何进行垃圾邮件分类的?假设“我公司可以提供发票、军售、航母维修”这句话不是垃圾邮件?P1("垃圾邮件"|"我司可提供发票、军售、航母维修")=p("垃圾邮件")p("我司可提供发票、军售、航母维修"/"垃圾邮件")/p("我司可提供发票、军售、航母维修")=p("垃圾邮件")p("发票","军火","航母"/"垃圾邮件")/p("发票","军火","航母")同理P2("普通邮寄"|"我司可提供发票,军售,航母维修")=p("普通邮寄")p("发票","arms","aircraftcarrier"/"normalmail")/p("invoice","arms","aircraftcarrier")我们只需要比较p1和p2的大小,就可以直接写成:P1("垃圾邮件"|"我司可提供发票、军售、航母维修")=p("垃圾邮件")p("发票"/"垃圾邮件")p("军火"/"垃圾邮件")p("航母"/"垃圾邮件")P2("普通邮件"|"我司可提供发票、军售、航母维修")=p("普通邮件pieces")p("invoice"/"normalmail")p("arms"/"normalmail")p("aircraftcarrier"/"normalmail")但是,我们看到无论是“我公司可以提供发票,“军售,航母维护”这几个词的顺序怎么变,不会影响它最后的结果判断,但是我们需求里面买的越早的项目,对后面的项目影响就越大。冰箱=>洗衣机=>衣柜=>电视=>苏打水,这个订单流程是合理的。冰箱=>洗衣机=>汽水=>电视=>衣柜,这个点餐流程相对来说可能性不大。但对于朴素贝叶斯,它们是相同的。所以,这里我们考虑顺序,或者上面的垃圾邮件问题。P1("垃圾邮件"|"我司可提供发票、军售、航母维修")=p("垃圾邮件")p("发票")p("军火"/"发票")p("军火"/"航母")P1("平邮"|"我司可提供发票,军售,航母维修")=p("平邮")p("发票")p("军火"/"发票")p("Arms"/"AircraftCarrier")在这里我们只依赖于每个单词的前一个单词。理论上,依赖1-3个词通常是可以接受的上面考虑顺序的贝叶斯是基于著名的马尔可夫假设(MarkovAssumption):下一个词的出现只取决于它前面一个或几个词下的联合概率问题,相关详细的理论数学公式没有给出,这里涉及到一个思想。02.第二部分:哈夫曼编码的大数据存储形式。我们常用的用户到物品的映射,就是通过一次热编码的形式实现的。这有一个很大的缺点就是数据存储系数和维度灾难的可能性非常高。.回到原来的那组数据:苏宁现在拥有约4亿种商品,10000多个商品品类,近40个大品类,现在会员数量已经达到3亿。如果需要建立一个用户产品对应的购买关系矩阵,进行基于用户的协同推荐,我们需要做一个4亿X6亿的1/0矩阵,这几乎是不可能的。霍夫曼采用近似二叉树的形式进行存储。下面以Tesco的采购量为例,说明如何以二叉树的形式替换onehotencoding存储方式:假设818苏宁大促期间,统计后有冰箱=>洗衣机=>烘干机=>电视=>衣柜=>钻石用户下单链(购买物品顺序同上),共15万台冰箱,8万台洗衣机,6万台烘干机,5万台电视机,共3万个衣柜并售出了10,000颗钻石。哈夫曼树构建过程:给定{15,8,6,5,3,1}作为二叉树的节点,每棵树只有一个节点,则有6棵独立的树。选择节点权重值最小的两棵树进行合并,即{3}和{1},计算合并后的新权重3+1=4。从节点列表中删除{3}、{1}树,将新的3+1=4组合树放回原节点列表。重复2-3,直到只剩下一棵树。对于每一层的每一个分支过程,我们可以把拥有权大的节点看成1,权值小的节点看成0,反之亦然。现在比如我们要知道钻石的编码是1000,也就是灰框所在的位置,洗衣机的编码是111,这种存储就是利用了0/1的存储方式,并且还考虑了组合位置的排列长度,节省了数据存储空间。03.第三部分:节点概率最大化当前数据可能出现的概率密度函数。对于菱形的位置,它的霍夫曼编码是1000,也就是说每次二进制选择都需要赋值一次。1,三次赋值为0。并且在每次划分的过程中,只能选择1/0。这是不是类似于逻辑回归中的0/1分类,所以这里我们也直接使用lr中的交叉熵作为损失函数。其实对于很多机器学习算法来说,都是基于先假设一个模型,然后构造一个损失函数,用数据训练损失函数,找到argmin(损失函数)的参数,然后放回原来的模型.让我们详细看一下这个菱形的例子:第一步:p(1|第1层未知参数)=sigmoid(第1层未知参数)第二步:p(0|第2层未知参数)=sigmoid(第2层未知参数)同理,第3层和第4层:p(0|第3层未知参数)=sigmoid(第3层未知参数)p(0|第3层未知参数).4层参数)=sigmoid(第4层未知参数)然后计算p(1|第1层未知参数)xp(0|第2层未知参数)xp(0|第2层未知参数)No.3layer)xp(0|No.4Unknownparameteroflayer)最大值对应的各层未知参数即可。求解方法与logistic求解方法类似,采用未知参数分布的偏导数,后续采用梯度下降法。(极大、批量、牛顿点播)04.第四部分:近似神经网络产品的相似性。刚才第三部分有个p(1|No.1层未知参数)的逻辑,这个NO.1层未知参数之一就是乘积向量。例如:有1000万用户按照“啤酒=>西瓜=>剃须刀=>百事可乐”的顺序购买过商品。如果按照naviebayes或n-grams等传统概率模型来看,10万用户有过“啤酒=>苹果=>剃须刀=>百事可乐”的购买顺序。P(beer=>watermelon=>razor=>Pepsi)>>p(beer=>apple=>razor=>Pepsi),但其实两个人应该是同一波人,他们的属性特征一定是相同的。在我们这边,我们随机初始化每个商品的特征向量,然后通过第三部分的概率模型进行训练,最后确定词向量的大小。另外,这样的事情也可以通过神经网络算法来完成。详细的方法在Bengioetal.,《A Neural Probabilistic Language Model》,2001年发表在NIPS中。这里需要知道的是,对于最小维度的商品,我们将0-1点(0,0,0,0,0,1,0,0,0,0...),单个商品向量是没有意义的。但是对于成对的商品向量,我们可以比较它们之间的余弦相似度,比较类别的相似度,甚至类别的相似度。Python代码实现01.数据读取#-*-coding:utf-8-*-importpandasaspdimportnumpyasnpimportmatplotlibasmtfromgensim.modelsimportword2vecfromsklearn.model_selectionimporttrain_test_splitorder_data=pd.read_table('C:/Users/17031877/Desktop/Sudeordert=cross_sell_tdata)1xalder'_data'.,axis=1)dealed_data=pd.DataFrame(dealed_data).fillna(value='')02.简单的数据合并和排序#datamergingdealed_data=dealed_data['top10']+[""]+dealed_data['top9']+[""]+dealed_data['top8']+[""]+\dealed_data['top7']+[""]+dealed_data['top6']+[""]+dealed_data['top5']+[""]+dealed_data['top4']+[""]+dealed_data['top3']+[""]+dealed_data['top2']+[""]+dealed_data['top1']#Datasplitdealed_data=[s.encode('utf-8').split()forsindealed_data]#数据拆分train_data,test_data=train_test_split(dealed_data,test_size=0.3,random_state=42)03.模型训练#原始数据训练#sg=1,skipgram;sg=0,SBOW#hs=1:hierarchicalsoftmax,huffmantree#nagative=0非负采样模型=word2vec.Word2Vec(train_data,sg=1,min_count=10,window=2,hs=1,negative=0)接下来就是用模型训练得到我们推荐的商品了。这里有三个思路,可以根据具体的业务需求和实际数据量来选择:相似商品映射表#最近浏览过的商品最相似的商品组top3x=1000result=[]result=pd.DataFrame(result)foriinrange(x):test_data_split=[s.encode('utf-8').split()forsintest_data[i]]k=len(test_data_split)last_one=test_data_split[k-1]last_one_recommended=model.most_similar(last_one,topn=3)tmp=last_one_recommended[0]+last_one_recommended[1]+last_one_recommended[2]last_one_recommended=pd.concat([pd.DataFrame(last_one),pd.DataFrame(np.array(tmp))],axis=0)last_one_recommended=last_one_recommended.Tresult=pd.concat([pd.DataFrame(last_one_recommended),result],axis=0)考虑用户上次操作的商品x,去掉那些用户已经购买过的商品.剩下的item表示用户仍然感兴趣但是因为没有找到合适或者便宜的item,通过商品向量之间的相似度,可以直接计算出高度相似的商品推荐给最有可能购买商品的用户。根据用户历史上还购买的产品顺序,根据当前目标用户最近购买的产品进行判断,然后他最有可能购买的是什么?例如,历史数据告诉我们,购买过手机+电脑的用户,最有可能在下周购买背包。然后我们会把电脑包产品推送给那些最近购买了电脑+手机的用户,激发他潜在的购物需求。#向量库rbind_data=pd.concat([order_data['top1'],order_data['top2'],order_data['top3'],order_data['top4'],order_data['top5'],order_data['top6'],order_data['top7'],order_data['top8'],order_data['top9'],order_data['top10']],axis=0)x=50start=[]output=[]score_final=[]foriinrange(x):score=np.array(-100000000000000)name=np.array(-100000000000000)newscore=np.array(-100000000000000)tmp=test_data[i]k=len(tmp)last_one=tmp[k-2]tmp=tmp[0:(k-1)]forjinrange(number):tmp1=tmp[:]target=rbind_data_level[j]tmp1.append(target)test_data_split=[tmp1]newscore=model.score(test_data_split)ifnewscore>score:score=newscorename=tmp1[len(tmp1)-1]else:passstart.append(last_one)output.append(name)score_final.append(score)联想记忆推荐在最可能的购买项目中,我们基于该用户近期的购买行为,从历史用户的购买行为数据中发现规律,并提供推荐产品。还有一个大概的逻辑,就是根据目标用户的最近一次购买,参考历史用户单次购买附近的数据进行推测。具体如下:这个实现也很简单,我这里就不写代码了,我就不贴了,我还是在word2vec中使用predict_output_word(context_words_list,topn=10),报告给定上下文词作为训练模型输入的中心词的概率分布。上面的细节做起来还是比较复杂的。我也在这里简单贴出一些想法,供大家参考和实践。