大数据 17、单机推荐系统

你挡我一时,挡不了我一世

发布日期: 2019-05-27 18:11:17 浏览量: 438
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

前文链接:https://write-bug.com/article/2491.html

通过前面介绍的算法基础,我们可以利用CB、CF算法作召回和粗排,利用LR作精排打分,最后关联出特定用户正在收听的特定音乐的推荐集合,最终形成可视化页面。

上图是推荐系统的base版本,可通过前几节的知识串接起来,后面会陆续介绍可替换的组件及更多业务情况。

我们可以看到用户在页面浏览时,可以通过点击、收听等行为我们进行user_id,item_id的收集,与此同时,我们使用用户的行为信息对检索引擎进行检索,即召回阶段的计算结果,之后我们需要对返回的候选集合进行精排,通过lr对用户特征+物品元数据信息作回归打分从而把筛选的候选集合再次排序,实现个性化。

项目流程:

1.数据准备

  • 用户画像数据:user_profile.data
    userid,性别,年龄,收入,地域

  • 物品(音乐)元数据:music_meta
    itemid,name,desc,时长,地域,标签

  • 用户行为数据:user_watch_pref.sml
    userid,itemid,该用户对该物品的收听时长,点击时间(小时)

首先,将3份数据融合到一份数据中,python gen_base.py 代码解析数据,实现对数据的拼接;得到数据merge_base.data。

  • 输入:user_profile.data music_meta user_watch_pref.sml 三份数据

  • 输出:merge_base.data 拼接后的数据

也可用hive处理:

  1. create external table user_profile(
  2. user_id string,
  3. sex string,
  4. age string,
  5. money string,
  6. place string
  7. ) row format delimited fields terminated by ',';
  8. load data local inpath '/usr/local/src/code/recsys_test/data/user_profile.data' into table user_profile;
  9. create external table music_meta(
  10. item_id string,
  11. name string,
  12. desc string,
  13. hour string,
  14. place string,
  15. tag string
  16. ) row format delimited fields terminated by '\001';
  17. load data local inpath '/usr/local/src/code/recsys_test/data/music_meta' into table music_meta;
  18. create external table user_watch_pref (
  19. user_id string,
  20. item_id string,
  21. listen_hour string,
  22. hour string
  23. ) row format delimited fields terminated by '\001';
  24. load data local inpath '/usr/local/src/code/recsys_test/data/ user_watch_pref.sml ' into table user_watch_pref;
  25. 3张表数据融合为一份数据
  26. user_watch_pref user_id,item_id,listen_hour,hour,
  27. user_profile sex,age,money,place
  28. music_meta name,desc,hour,place
  29. insert overwrite directory '/data' row format delimited fields terminated by ','
  30. select distinct(a.user_id),a.item_id,a.listen_hour,a.hour,c.sex,c.age,c.money, c.place,b.name,b.desc,b.hour,b.place
  31. from user_watch_pref as a, user_profile as c,music_meta as b
  32. where a.user_id = c.user_id and a.item_id=b.item_id;

2.召回、CB算法

在学习推荐算法时,我们可以发现,不管是cb还是cf都可以通过对mr倒排式的协同过滤算法对数据进行处理,只是token item_id,score和user item_id,score 的区别。

以token itemid score形式整理训练数据

gen_cb_train.py 我们这里的代码对item的name,desc,tag进行分词并给予不同的权重便可以形成我们的数据。

  • 输入:merge_base.data 总数据

  • 输出:cb_train.data 3列数据

要点:对item_id 进行去重,对不同元数据分词分数给予不同权重,如果音乐名字、描述、标签中出现相同的token,我们就把相应的分数乘各自的权重相加,如果不相同便加入token字典

  1. RATIO_FOR_NAME = 0.9
  2. RATIO_FOR_DESC = 0.1
  3. RATIO_FOR_TAGS = 0.05

用协同过滤算法跑出item-item数据 mr_cf倒排式

最后得到基于cb的ii矩阵,这里我也用hive弄了下,但是没想到怎么整理出ii矩阵:

  1. cb_train.data
  2. token,item_id,tfidf
  3. create external table cb_train (
  4. token string,
  5. item_id string,
  6. tfidf string
  7. ) row format delimited fields terminated by ',';
  8. load data local inpath '/usr/local/src/code/recsys_test/data/cb_train.data into table cb_train;
  9. token,item_id,score
  10. sum(sqrt(sum(s^2))):
  11. select token,item_id,sum(power(tfidf,2)) over(partition by item_id) as score
  12. from cb_train order by item_id limit 100;
  13. s/sum(sqrt(sum(s^2))):
  14. insert overwrite directory '/data/cb_z' row format delimited fields terminated by ','
  15. select t.token,t.item_id,cb_train.tfidf/sqrt(score) as f_score
  16. from
  17. (select token,item_id,sum(power(tfidf,2)) over(partition by item_id) as score
  18. from cb_train)t,cb_train
  19. where t.item_id=cb_train.item_id and t.token = cb_train.token;
  20. limit 300;
  21. 暂存:token,item_id,score
  22. create external table cb_train_score (
  23. token string,
  24. item_id string,
  25. score string
  26. ) row format delimited fields terminated by ',';
  27. load data inpath '/data/cb_z/000000_0'
  28. into table cb_train_score;

对数据格式化,item-> item list形式,整理出KV形式

gen_reclist.py并标记数据计算算法:

  • 输入:cb.result ii矩阵

  • 输出:cb_reclist.redis 粗排、标记、聚合

类似如下数据:

  1. SET CB_5305109176 726100303:0.393048_953500302:0.393048_6193109237:0.348855

灌库(redis)

下载redis-2.8.3.tar.gz安装包,进行源码编译,执行make,然后会在src目录中,得到bin文件(redis-server 服务器,redis-cli 客户端)。

启动redis server服务:

  1. ]# ./src/redis-server

然后换一个终端执行:]# ./src/redis-cli,连接服务

接下来灌数据(批量灌):

需要安装unix2dos(格式转换)

  1. ]# cat cb_reclist.redis | /usr/local/src/redis-2.8.3/src/redis-cli --pipe

验证:

  1. ]# ./src/redis-cli

执行:

  1. 127.0.0.1:6379> get CB_5305109176
  2. "726100303:0.393048_953500302:0.393048_6193109237:0.348855"

3.召回、CF算法

以userid itemid score形式整理训练数据 gen_cf_train.py

得到userid对item的最终分数,即user收听时长表示对item的喜欢分数 score = float(t_finished) / float(t_all)

用协同过滤算法跑出item-item数据 mr_cf,最后得到基于cf的ii矩阵

对数据格式化,item-> item list形式,整理出KV形式

  1. unix2dos cf_reclist.redis

灌库

  1. cat cf_reclist.redis | /usr/local/src/redis-2.8.3/src/redis-cli pipe

与上面cb算法一样流程.

4.为lr模型作特征提取:

  • user: gender、age

  • item:name_token

  • 输入:merge_base.data

  • 输出:

    • samples.data 特征提取数据
    • user_feature.data 用户特征数据,为使用模型作数据准备
    • item_feature.data 物品特征数据,为使用模型作数据准备
    • name_id.dict 为包装数据作准备

这里的label值用用户的收听时长来作判断:

  1. # label info
  2. label = float(watch_time) / float(total_time)
  3. final_label = '0'
  4. if label >= 0.82:
  5. final_label = '1'
  6. elif label <= 0.3:
  7. final_label = '0'
  8. else:
  9. continue

用户特征分数初始化为1,物品特征分数运用jieba分词的idf作为初始分数

形成如下数据:

模型使用时,只有w,b 怎么使用,我需要有个库去存储user_fea、item_fea。实时拼接出特征,再通过model预测。

用sk-learn进行模型训练,得到w,b。解析samples数据,还原矩阵:

  • target_list:存储每个样本的label标签

  • fea_row_list:存储样本行信息

  • fea_col_list:存储样本列信息

  • data_list:存储真实数据score

转换数据并分割数据集:

  1. fea_datasets = csr_matrix((data, (row, col)), shape=(row_idx, max_col + 1))
  2. x_train, x_test, y_train, y_test = train_test_split(fea_datasets, target_list, test_size=0.2, random_state=0) # 28分为测试集及训练集

训练

  1. x_train, x_test, y_train, y_test = load_data()
  2. model = LogisticRegression(penalty='l1')
  3. model.fit(x_train, y_train)
  4. for w_list in model.coef_:
  5. for w in w_list:
  6. print >> ff_w, "w: ", w
  7. for b in model.intercept_:
  8. print >> ff_b, "b: ", b
  9. print "precision: ", model.score(x_test, y_test)#预测
  10. print "MSE: ", np.mean((model.predict(x_test) - y_test) ** 2)#误差平方根

auc评估

  1. for y in y_test:
  2. print >> ff_t, y
  3. for y in model.predict_proba (x_test):
  4. print >> ff_p, y
  • 评估:auc:paste T.txt P.txt >auc.txt,awk无图形测试:但是需要回归的浮点分数不能用分类的label

  • 回归:model.predict_proba()

  • 分类:model.predict() :0&1

5.推荐引擎及可视化

通过前面的层层处理,我们得到了user&item特定的候选集合如何随意来了一个用户推荐个性化呢?

  • 解析请求:userid,itemid,pyweb模拟页面

  • 加载模型:加载排序模型(model.w,model.b),加载并解析数据

  • 检索候选集合:利用cb,cf去redis里面检索数据库,得到候选集合。截断粗排候选集合,得到item_list

  • 获取用户特征:userid

  • 获取物品特征:itemid,这两步用到上面说的特征库

  • 打分(逻辑回归),排序。对拼接出的特征进行检索wx计算,更新分数,并通过sigmoid函数压缩分数

  • top-n过滤

  • 数据包装(itemid->name),返回

之后,再把最终的候选集合列表,post到前端页面。

此上,即为单机版本的推荐系统实现,但是在工作中思路大概是这样,只是拓宽了算法组件、机器、备份、分流等等东西,需要多个部门共同协作。

上传的附件
最近文章
eject