1.以用户为基础的协同过滤
基于用户对某些商品进行打分
*1.1相似度运算:
1.1.1欧几里得距离评价
1.1.2皮尔逊相关度评价
依旧对商品进行打分
1.1为用户推荐商品 (加权排序推荐)
1.2算法缺点
2.基于物品的协同过滤算法
2.1基于物品对用户进行打分
2.1 相似度评价
皮尔逊相关度评价
通过计算可以发现,商品1&2,商品3&4&5的相似度较⾼。下⼀步我们可以依据这些商品间的相关度对⽤户进⾏商品推荐。
2.2 为⽤户提供基于相似物品的推荐
协同过滤优缺点
3.基于内容的推荐算法
数据集读取
数据集包含了某新闻类APP上近12个⽉内的⽤户⾏为数据、以及具体的新闻⽂章内容。
现在需要根据⽂章的内容、⽤户和⽂章的互动⾏为数据,基于推荐算法,为⽤户推荐他可能会感兴趣且尚未看过的新闻⽂章。
数据集由2个csv⽂件组成:
shared_articles.csv: ⽂章的具体内容数据
users_interactions.csv: ⽤户与⽂章互动的⾏为数据(分享⽂章)
import numpy as np
import scipy
import pandas as pd
import math
import random
import sklearn
from nltk.corpus import stopwords
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from scipy.sparse.linalg import svds
import matplotlib.pyplot as plt
⽂章的具体内容(shared_articles.csv)
⽂章的具体内容数据中,还包括⽂章被操作的时间、⽂章id、作者id、作者所在地等。
⽂章的操作类型(eventType)包括content shared与content removed;为了简化问题,我们仅考虑被分享过的⽂章。
# 读取⽂章的具体内容数据 为articles_df,articles_df的每条记录均有对应的contentId
articles_df = pd.read_csv('shared_articles.csv')
articles_df = articles_df[articles_df['eventType'] == 'CONTENT SHARED'] #我们仅考虑被分享过的⽂章
articles_df.head(3)
⽤户与⽂章互动的⾏为数据(users_interactions.csv)
#⽤户与⽂章互动的⾏为数据(users_interactions.csv)
#users_interactions.csv是⽤户与⽂章互动的⾏为数据
#⾏为类型有:
“”"
VIEW: 浏览
LIKE: 点赞
COMMENT CREATED: 评论
FOLLOW: 关注该⽂章
BOOKMARK: 给⽂章地址加书签
“”"
# 每条记录由 contentId与personId 的组合来对应
interactions_df = pd.read_csv('C:/Users/lb/Desktop/test/users_interactions.csv')
interactions_df.head(3)
#users_interactions.csv之后可以与articles_shared.csv 连接,连接键为 contentId
数据处理
基于⽤户与⽂章的互动⾏为建⽴量化体系、统计评分数据
我们需要对不同的⾏为类型赋予合适的评分,之后才能量化⽤户的互动⾏为数据,⽐如评论的分数会⾼于浏览与点赞的分数。
基于⽤户对⽂章的互动⾏为数据构建评分体系,⽬的是科学地评估⽤户对不同⽂章感兴趣的程度,进⽽去做推荐。
event_type_strength = {
'VIEW': 1.0,
'LIKE': 2.0,
'BOOKMARK': 2.5,
'FOLLOW': 3.0,
'COMMENT CREATED': 4.0,
}
# 评论的分数最⾼,其次是关注,然后是保存地址于书签。
# 基于评分标准,量化⽤户的互动⾏为数据
interactions_df['eventStrength'] = interactions_df['eventType'].apply(lambda x: event_type_strength[x])
也有类似采用replace()的用法
# status_replace = {
# "eventType" :{
# 'VIEW':1.0,
# 'LIKE':2.0,
# 'BOOKMARK':2.5,
# 'FOLLOW':3.0,
# 'COMMENT CREATED':4.0,
# }
# }
# ## 评论的分数最⾼,其次是关注,然后是保存地址于书签。
# # 基于评分标准,量化⽤户的互动⾏为数据
# interactions_df = interactions_df.replace(status_replace)
基于冷启动问题,只取⽂章互动次数在5次及以上的⽤户
由于推荐系统存在冷启动的问题,即很难为那些尚未买过⼀定数量的物品(或接触过⼀定数量的⽂章)的⽤户提供个性化的推荐,因为历史数据中他们买过的物品(接触的⽂章)的信息有限。
因此我们⽬前的案例只对互动过的⽂章数在5篇及以上的⽤户进⾏研究。
现在我们要计算每个⽤户互动过的⽂章数量,然后再限制数量>=5,把互动⽂章数超过5的⽤户筛选出来。
df.groupby(‘personId’).size() 和
df.groupby([‘personId’, ‘contentId’]).size().groupby(‘personId’).size() 的区别
interactions_df.groupby('personId').size()
interactions_df.groupby('personId')['contentId'].count()
上⾯这两种⽅法都没有对contentId去重
去重办法:
利用groupby 进行去重
interactions_df.groupby(['personId', 'contentId']).size().groupby('personId').size()
验证:
loc[] 表根据标签或者索引
len(interactions_df.loc[interactions_df['personId']==-9212075797126931087, 'contentId'].unique())
users_interactions_count_df
#区别在于⼀个⽤户对同⼀篇⽂章可能有多次互动操作(包括浏览、分享、点赞等),因此如果仅仅df.groupby('personId').size() ,会包含重复的数量。
users_interactions_count_df = interactions_df.groupby(['personId', 'contentId']).size().groupby('personId').size()
print('# users: %d' % len(users_interactions_count_df))
对聚合操作后的数据(此时已经是从dataframe转换至series),那么就需要进行series至dataframe的转换。
使用reset_index() 就可以转换成dataframe
pandas小技巧将Series转换为DataFrame
https://zhuanlan.zhihu.com/p/64083572
计算每个⽤户互动过的⽂章数量,然后再限制数量>=5,把互动⽂章数超过5的⽤户筛选出来。
# 计算每个⽤户互动过的⽂章数量,然后再限制数量>=5,把互动⽂章数超过5的⽤户筛选出来。
users_with_enough_interactions_df = users_interactions_count_df[users_interactions_count_df >= 5].reset_index()[['personId']]
print('# users with at least 5 interactions: %d' % len(users_with_enough_interactions_df))
变成dataFRAME 了
#[[‘personId’]]和[‘personId’]的区别
用户操作数量大于5篇文章 那些用户id 与原表进行匹配
interactions_from_selected_users_df
interactions_from_selected_users_df = interactions_df.merge(users_with_enough_interactions_df,
how = 'inner',
on = 'personId')
len(interactions_from_selected_users_df)
4.构建⽤户-物品评分数据表
由于⽤户可能会多次浏览、评论同⼀篇⽂章,所以我们在量化⽤户对某⼀篇⽂章的⾏为数据时,是先将⽤户的⾏为赋值、然后加和得到⼀个互动数值。所以现在我们要做的就是加和。
同时我们对最后的互动数值取对数值,使得其分布更符合正态分布且更平滑。
用np.log() 不合适 不清楚数据类型
def smooth_user_preference(x):
return math.log(1+x, 2)
interactions_full_df = interactions_from_selected_users_df \
.groupby(['personId', 'contentId'])['eventStrength'].sum() \
.apply(smooth_user_preference).reset_index()
print('# of unique user/item interactions: %d' % len(interactions_full_df))
interactions_full_df.head(10)
或者:a = interactions_from_selected_users_df.groupby(['personId','contentId'])['eventStrength'].sum().apply(lambda x :math.log(1+x, 2) )\ .reset_index() #reset_index() ,改成dataFRAME
5.具体的推荐算法
对推荐算法效果的评估是⼗分重要的,这⾥我们使⽤了交叉验证⽅法,即随机取20%的数据集作为测试集,80%的数据集作为训练集。
stratify参数作用
interactions_train_df, interactions_test_df = train_test_split(interactions_full_df,
stratify=interactions_full_df['personId'],
test_size=0.20,
random_state=42)
print('# interactions on Train set: %d' % len(interactions_train_df))
print('# interactions on Test set: %d' % len(interactions_test_df))
6.Top-N推荐的准确性评测
使⽤personId(⽤户id)作为⽤户-物品评分数据集的索引,提⾼之后获取数据的速度
使⽤personId(⽤户id)作为⽤户-物品评分数据集的索引
# 使⽤personId(⽤户id)作为⽤户-物品评分数据集的索引,提⾼之后获取数据的速度
interactions_full_indexed_df = interactions_full_df.set_index('personId')
interactions_train_indexed_df = interactions_train_df.set_index('personId')
interactions_test_indexed_df = interactions_test_df.set_index('personId')
def get_items_interacted(person_id, interactions_df):
#集合可以相减
#集合可以相减
def get_items_interacted(person_id, interactions_df):
# Get the user's data and merge in the movie information.
#得到指定得person_id 的所对应的那些contentId
interacted_items = interactions_df.loc[person_id]['contentId']
return set(interacted_items if type(interacted_items) == pd.Series else [interacted_items])
按照索引之后 跳了一步
7.Top-N推荐的准确性评测⽅法
# Top-N推荐的准确性
EVAL_RANDOM_SAMPLE_NON_INTERACTED_ITEMS = 100
class ModelEvaluator:
下面都是上面的子函数
⽤于随机取出 sample_size篇、先前该⽤户没有互动过的⽂章
# ⽤于随机取出 sample_size篇、先前该⽤户没有互动过的⽂章
def get_not_interacted_items_sample(self, person_id, sample_size, seed=42):
interacted_items = get_items_interacted(person_id, interactions_full_indexed_df)
#全部的文章
all_items = set(articles_df['contentId'])
#减去指定得文章(即互动过的文章&