推荐系统实现相似推荐的流程和资源

视频位于:链接

需要的资源整理:

本视频涉及的相关资源:

1、jieba中文分词库:

https://github.com/fxsjy/jieba

2、spark word2vec计算:

http://spark.apache.org/docs/latest/ml-features.html#word2vec

3、腾讯开源800万word2vec数据:

https://ai.tencent.com/ailab/nlp/embedding.html

4、Scipy的相似度计算函数:

https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.distance.cosine.html

5、相似度近邻搜索优化算法LSH局部敏感哈希

http://spark.apache.org/docs/latest/ml-features.html#locality-sensitive-hashing

 

推荐系统:实现文章相似推荐的简单实例

看了一篇文章实现了文章的内容相似度计算实现相似推荐,算法比较简单,非常适合我这种初学入门的人。

来自一篇英文文章:地址

文章标题为:How to build a content-based movie recommender system with Natural Language Processing

文章的代码在:地址

该文章实现相似推荐的步骤:

1、将CSV加载到pandas.pd

2、提取其中的标题、题材分类、导演、演员、情节描述4个字段;

3、将单词都变小写,人名中的空格合并(英文才需要这样);

4、题材分类、导演、演员这几个特征都是结构化的不需要处理;而标题、情节描述这类字段是长段文本,使用nltk库做关键词提取(如果是中文可以用jieba分词库也有关键词提取功能)

5、将第四步骤的分类、导演、演员、关键词列表,合并到一个词列表(这一处理其实暗含了分类、导演、演员三个特征和关键词一样重要,没有做加权处理)

6、使用CountVectorizer做每个词语的计数,得到了每个文章的向量;

7、使用sklearn的cosin做笛卡尔积的相似度计算;

8、计算结果是一个二维矩阵,按行查询某一个文章的推荐结果,按相似度值排序得到最相似的文章

从里面能学到不少知识的运用:

1、全流程用pandas运行,尤其是for each row,做单个列的各种map计算;

2、计算相似度时使用了多个特征,包括Title,Genre,Director,Actors,Plot,统一成一个bag of words参与计算

3、使用from sklearn.metrics.pairwise import cosine_similarity用于相似度计算;

4、使用from sklearn.feature_extraction.text import CountVectorizer用于单词计数;

5、使用from rake_nltk import Rake用于关键词提取;

代码实现关键部分:

作者用到的一些库:

import pandas as pd
from rake_nltk import Rake
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.feature_extraction.text import CountVectorizer

pandas的dataframe中,直接替换一列的语法:

df['Director'] = df['Director'].map(lambda x: x.split(' '))

pd按行以此处理某个列的方法:

for index, row in df.iterrows():
    row['Actors'] = [x.lower().replace(' ','') for x in row['Actors']]
    row['Director'] = ''.join(row['Director']).lower()

pd.df删除某一列的方法:

df.drop(columns = ['Plot'], inplace = True)

pd.df从columns中提取一列作为index的方法:

df.set_index('Title', inplace = True)

作者将能使用的所有列,都放在了一个词包中用于相似度计算,按我的想法,这些特征列其实应该有不同的权重?

df['bag_of_words'] = ''
columns = df.columns
for index, row in df.iterrows():
    words = ''
    for col in columns:
        if col != 'Director':
            words = words + ' '.join(row[col])+ ' '
        else:
            words = words + row[col]+ ' '
    row['bag_of_words'] = words
    
df.drop(columns = [col for col in df.columns if col!= 'bag_of_words'], inplace = True)

sklearn使用词计数的调用:

count = CountVectorizer()
count_matrix = count.fit_transform(df['bag_of_words'])

sklearn实现矩阵相似度计算的方法:

# generating the cosine similarity matrix
cosine_sim = cosine_similarity(count_matrix, count_matrix)

怎样实现不同特征列的融合相似度计算?

这个问题纠结我很久,查询了一些文章,大都是人工指定加权权重,或者使用模型拟合权重值,没有多么简单的方法,而作者使用的其实是直接把分类、演员等字段,和关键词直接融合的方法

作者在文章中提到一句话:

I decided to use CountVectorizer rather than TfIdfVectorizer for one simple reason: I need a simple frequency counter for each word in my bag_of_words column. Tf-Idf tends to give less importance to the words that are more present in the entire corpus (our whole column, in this case) which is not what we want for this application, because every word is important to detect similarity!

对于标题、介绍这种纯文本内容,我们可以用TF/IDF提取关键词,物理含义就是降低全局出现的词频很多的词语;但是其实对于作者、演员、题材这类特征列,他们并不需要降低全局词频,使用词频计数即可。

有哪些可以提升的地方

作者的方法确实可以实现相似推荐,不过我感觉有一些可以提升的地方:

1、标题、简介,提取关键词后,可以查询业界的word2vec做向量扩展,这样能实现恰恰和伦巴舞这类词语的相似度度量,直接的关键词查询是得不到这样的信息;

2、分类、导演、演员这三个特征,需要和描述得到的关键词区分开,可以用加权的方法进行,按照产品的需求,加重分类、导演的相似度权重,降低演员、关键词的权重等,如果需要可以从点击率等出发,用模型计算这些权重;

本文地址:http://www.crazyant.net/2454.html,转载请注明来源

 

Spark使用word2vec训练item2vec实现内容相关推荐

之前使用spark als训练协同过滤,然后导出itemvectors做相似度计算,后来学到了可以用word2vec实现item2vec的训练效果貌似更好,试了一下果然不错;

spark版本:2.3.1,开发语言为JAVA

几大步骤

  1. 读取查看、点击、播放等行为数据,我用的是播放数据;
  2. 数据整理成(userid, itemid, playcnt)的形式,这个数据可能是聚合N天得到的;
  3. 过滤掉playcnt为小于3的数据,我把这些过滤掉,觉得这个数据没有贡献;
  4. 按照userid聚合,得到(userid, list(itemid))的形式;
  5. 训练word2vec;
  6. 导出model.vectors(),里面包括word和对应的向量vector,其中word其实就是itemid
  7. crossjoin计算两两相似度,取相似度TOP N;
  8. 将结果存入mysql,后续可以加载到REDIS实现实时相似推荐;

代码实现

读取播放数据:

Dataset<Row> playDatas = spark.sql(
        "select user_id, item_id, play_cnt " +
                "from hive_play_table group by user_id, item_id");

 

做数据按userid聚合:

playDatas = playDatas
        // 删除掉只播放3次以下的数据
        .filter("play_cnt>2")
        // 按userid聚合
        .groupBy("user_id")
        .agg(collect_list("item_id").as("item_ids"))
        // 至少操作过2个元素
        .where(size(col("item_ids")).geq(2));

 

训练word2vec:

Word2Vec word2Vec = new Word2Vec()
        .setInputCol("item_ids")
        .setOutputCol("word2vec_result")
        .setVectorSize(50)
        .setMinCount(0)
        .setMaxIter(50)
        .setSeed(123);

Word2VecModel word2VecModel = word2Vec.fit(playDatas);

 

实现df的cross join:

Dataset<Row> vectorsA = word2VecModel
        .getVectors()
        .select(
                col("word").as("itemIdA"),
                col("vector").as("vectorA"));

Dataset<Row> vectorsB = word2VecModel
        .getVectors()
        .select(
                col("word").as("itemIdB"),
                col("vector").as("vectorB"));

// self cross join
Dataset<Row> crossDatas = vectorsA.crossJoin(vectorsB);

 

注册余弦相似度计算函数:

spark.udf().register(
        "vectorCosinSim",
        new UDF2<Vector, Vector, Double>() {
            @Override
            public Double call(Vector vectora, Vector vectorb) throws Exception {
                return SimilarityUtils.cosineSimilarity(vectora, vectorb);
            }
        },
        DataTypes.DoubleType
);

 

其中调用的余弦相似度计算函数,使用JAVA实现:

public static double cosineSimilarity(Vector featuresLeft, Vector featuresRight) {
    double[] dataLeft = featuresLeft.toArray();
    List<Float> lista = new ArrayList<>();
    if (dataLeft.length > 0) {
        for (double d : dataLeft) {
            lista.add((float) d);
        }
    }

    double[] dataRight = featuresRight.toArray();
    List<Float> listb = new ArrayList<>();
    if (dataRight.length > 0) {
        for (double d : dataRight) {
            listb.add((float) d);
        }
    }

    return cosineSimilarity(lista, listb);
}

 

实现相似度计算,并过滤掉自身和自身的计算:

crossDatas = crossDatas
        .withColumn(
                "cosineSimilarity", callUDF(
                        "vectorCosinSim", col("vectorA"), col("vectorB")))
        .select("itemIdA", "itemIdB", "cosineSimilarity")
        .filter(col("itemIdA").notEqual(col("itemIdB")));

 

使用 spark的Window,提取每个group的topn:

// 按照相似度倒序排列取TOP 300
WindowSpec windowSpec = Window.partitionBy("itemIdA").orderBy(col("cosineSimilarity").desc());
crossDatas = crossDatas
        .withColumn("simRank", rank().over(windowSpec))
        .where(col("simRank").leq(200));

 

将数据聚合成每个Item的推荐列表的形式:

crossDatas = crossDatas
        .groupBy("itemIdA")
        .agg(
                collect_list("cosineSimilarity").as("columnSims"),
                collect_list("itemIdB").as("itemIds")
        ).select(
                col("itemIdA").as("item_id").cast(DataTypes.LongType),
                col("columnSims").as("column_sims").cast(DataTypes.StringType),
                col("itemIds").as("item_ids").cast(DataTypes.StringType)
        );

 

将数据覆盖写入MySQL:

crossDatas.write().mode(SaveMode.Overwrite).jdbc(
        MysqlConfig.ONLINE_MYSQL_MASTER_URL,
        "item2vec_sims",
        MysqlConfig.getOnlineProperties()
);

 

在数据库中,我们根据item_id,提取到item_ids,可以用于直接的推荐;其中column_sims也记录了对应的相似度权重,如果需要加权的话也可以直接提取;

欢迎大家关注我的爱奇艺号,学习Pyton大数据人工智能技术,地址

本文地址:http://www.crazyant.net/2447.html,转载请注明来源。

 

 

 

推荐系统:怎样实现内容相似推荐

很多产品想要加入推荐系统模块,最简单的就是做内容相似推荐,虽然技术简单但是效果却很好,对于增加用户粘性、提升用户留存有较多的效果,甚至很多产品后来加入了很多推荐模块之后,还是发现导流效果最好的依然是内容的相似推荐。

比如看完了一片《Python怎样读取MySQL》之后,在相似推荐中看到了一片题目为《Python操作MySQL的效果优化》的文章,很自然的就像多深入了解一下,于是就点进去看一看,那么对于整个网站来说,就会降低跳出率,增加用户的留存,是一个很好的用户体验。

实现一个内容相似推荐的方案比较简单,大体上包含以下步骤:

1、获取内容数据,比如标题、关键字、分类、甚至全文本;

一般文档、数据等内容都存储于mysql,可以使用python/java等语言直接读取mysql导出到文件.txt格式,或者直接用shell的mysql -e sql > data.txt的方式导出。

一般情况下,全文本内容太散,不会作为候选字段,但是有些视频之类的实体,因为标题和简介文字太少,如果有详情全文本的话,也可以加入候选数据字段。

2、对内容数据做中文分词;

如果是python语言,可以使用“结巴分词”,地址为:https://github.com/fxsjy/jieba

或者可以直接使用百度云的中文分词,百度的NLP自然语言处理技术还是很厉害的。

3、提取内容数据的关键词;

当分词之后,分词结果中包含很多“的”、“也”等无意义的词语,这些词语不能称之为关键词,一般会通过TF/IDF的方法计算每个词语的权重,将一个文档的所有词语的TF/IDF权重倒序排列,取TOPN个作为关键词;

如果使用的是jieba分词,那么直接就自带了提取关键词的支持;当然也可以自己计算,TF就是计算一篇文章中每个词语出现的次数、IDF就是这个词语在所有文章中出现的次数,TF除以IDF就是权重值;

4、将关键词映射成数字向量;

我们最终的目标是计算文档之间的相似度,要计算相似度那就需要把内容映射成向量,第一步就是先把每个词语映射成向量,映射的方式有几种:

  • 使用one hot方法映射成向量
  • 自己训练word2vec密度向量;
  • 使用业界的训练好的word2vec向量

一般情况下,自己的数据集比较小,效果会比业界的word2vec效果差一些,比如这里推荐腾讯开源的200维度全网word2vec向量,地址在:https://ai.tencent.com/ailab/nlp/embedding.html

5、计算文档粒度的数字向量;

得到每个词语的向量之后,通过加权平均的方式可以计算整个文档的向量;

权重可以使用每个词语的频率次数归一化,或者直接平均即可;

6、计算文档之间的相似度;

使用cosin算法就能够计算文档向量之间的相似度;

cosin算法很简单,java、python自己实现就可以,也可用https://scikit-learn.org或者http://surpriselib.com/中的相似度计算模块直接调用实现。

计算完之后,对于每个文档,将它跟每个文档的相似度做倒序排列,比如TOP 30个作为推荐的结果集合。

7、将文档的相似度关系存入mysql/redis等缓存;

第6步骤会得到一个这样的结果:(文档ID、相似文档ID列表),将这样的数据直接存入mysql或者redis,key就是文档ID,value是相似文档ID列表即可。

8、当页面展示一个内容的时候,提取相似推荐进行展示;

当用户访问一个页面的时候,后端服务python/java从缓存redis或者mysql中根据展示的页面的文档ID,提取相似ID列表;

因为前几步骤是提前计算好的列表,这里也可能做一些过滤已下线的事情,然后根据ID提取对应的标题、简介等信息,组装成相似推荐列表返回给前端即可;

总结

以上就是离线计算相似推荐的步骤,其实还可以用在线的方式进行,把这个问题按照搜索的架构实现即可,新来一个文档就分词、计算关键词列表存储,然后每次访问的时候根据关键词列表查询相同关键词列表的文档也可以实现。

当相似内容推荐上线后,就能够不断积累一些用户点击、查看文档的行为数据,基于行为数据就能训练协同过滤的模型,实现内容不相似但是行为相似的协同过滤推荐。

推荐系统:爱奇艺知识推荐系统架构

爱奇艺知识频道当前已经包含了2万精品课程,涵盖职场、文史、IT/互联网等多个分类,这么多课程怎么实现高效分发是一个大难题,通过搜索触达、人工运营位、IP导流等方式确实可以分发一批课程,然而这些课程普遍集中于头部热度课程,暴露在用户面前的仍然是冰山的顶部,大量的课程由于信息过载没有暴露的机会,挖掘长尾课程防止过度马太效应,推荐系统责任重大。

1、表现形式

爱奇艺知识当前的推荐系统有如图几个表现形式:

  • 个性化分群运营:根据画像做用户分群,按群推荐课程;
  • 猜你喜欢:个性化课程推荐流;
  • 相关推荐:课程页面内的相关推荐;
  • 买了又买:购买成功页的课程推荐;

2、系统架构

系统架构上图,主要流程如下:

  • 数据处理:使用spark、hive、python,从mysql备库、hbase、pingback的hive表和实时流提取数据,实现关联、清洗、映射特征等处理,其中spark streaming从pingback的rockermq准实时提取用户行为,实现10秒钟用户个性化推荐列表的更新;
  • 模型计算:使用spark als矩阵分解计算,结果可以给用户推荐协同过滤、以及根据item vectors实现相关推荐;使用tensorflow/paddle实现排序模型,使用LR/DNN/DEEP&WIDE实现CTR排序;
  • 结果数据存储:这里涉及比较多的考虑,主要是从数据量、查询响应时间、数据结构支持度等方面考虑:
    • 对于item本身实体数据、item相似度列表等数据,使用redis存储,因为redis cluster不能够批量读取,但是这里却需要批量读取;
    • 对于用户行为实时数据,因为需要大数据量存储,并且需要丰富的数据结构支持,选用redis cluster;
    • 对于用户画像数据、自己提取的用户标签数据,数据量大,只需要根据用户ID提取,所以选用scylla;
  • 在线服务:主要是参考youtube的推荐系统架构,将整体步骤细分为召回、排序、过滤、混排等步骤,其中:
    • 召回、排序、已购等步骤,都是id在参与计算,等最终返回的时候,才查询实体业务数据;
    • 模型排序服务使用grpc/brpc/http提供服务给应用服务调用;
    • 应用服务同时需要支持AB Test的分桶,以及参数的返回;
  • 前端请求:前端只进行非常短暂的缓存(防止恶意请求),重要的是需要搞定pingback的埋点投递,投递中需要设定ab test的参数

以上就是爱奇艺知识的推荐系统架构,系统还处于快速迭代升级中,之后的事情有这些:

  • 当前系统在QPS高峰是耗时150MS左右,时间耗费在实体数据拼装阶段,后续进行优化;
  • 相关推荐的导流效果很好,后续进行多种实验进行效果对比;
  • 排序模型的线上化,通过AB测试进行效果对比;

 

本文地址:http://www.crazyant.net/2324.html,转载请注明来源