用矩阵分解来解决推荐问题

整体架构

  1. 读取数据
  2. 训练模型

分部细节

生成训练数据

从hadoop生成两个子文件
(1)docid,pv,cl
(2)mid,cl_docid_duration_dict, pv_docid_set
生成训练数据:
get_docid_doctype_videotime_by_kv.py
gen_mid_docid.py
gen_train_data.py
生成的结果是mid,docid,score其中score的计算是重点,如下:

def evaluate_score(docid_duration, docid_doctype_videotime_dict):
	items0 = docid_duration.split(':')
	if len(items0) != 2:
		return 0
		docid = items0[0]
		duration = int(items0[1]) if items0[1] != '0' else 5
		doctype, videotime = docid_doctype_videotime_dict[docid]
		if doctype == 0:
			duration = 180 if duration > 180 else duration
            score = 0.5 + 0.5 * (duration/180.0)
		if doctype == 1:
            videotime = 60 if videotime < 60 else (360 if videotime > 360 else videotime)
            duration = videotime if duration > videotime else duration
            score = 0.5 + 0.5 * (duration*1.0 / videotime) * (0.5 + 0.1 * (videotime - 60)/60.0)
        if doctype == 2:
            videotime = 10 if videotime < 10 else (360 if videotime > 360 else videotime)
            duration = videotime if duration > videotime else duration
            score = 0.5 + 0.5 * (duration*1.0 / videotime)
        return score

bm25矩阵分解

读取第一步得到的mid,docid,score,生成三个列表userid_list, itemid_list, score_list
训练模型,得到item和user的embedding

from scipy import sparse
import implicit
from implicit.nearest_neighbours import (BM25Recommender, CosineRecommender, TFIDFRecommender, bm25_weight)

def train_model():
        global userid_list, itemid_list, score_list, max_userid, max_itemid, csr_item_user_mat, model
        coo_user_item_mat = sparse.coo_matrix((score_list, (userid_list, itemid_list)), shape=(max_userid + 1, max_itemid + 1))
        coo_item_user_mat = coo_user_item_mat.T
        coo_item_user_mat = bm25_weight(coo_item_user_mat, K1=100, B=0.8)
        csr_item_user_mat = coo_item_user_mat.tocsr()
        model = implicit.als.AlternatingLeastSquares(factors=100, iterations=10, calculate_training_loss=True)
        model.fit(csr_item_user_mat)


def output_embedding(user_embedding_filepath, item_embedding_filepath):
        global model
        fw0 = open(user_embedding_filepath, 'w')
        fw1 = open(item_embedding_filepath, 'w')
        for i,emb in enumerate(model.user_factors):
            fw0.write(str(i) + '\t' + ','.join(map(str,emb)) + '\n')
        for i,emb in enumerate(model.item_factors):
            fw1.write(str(i) + '\t' + ','.join(map(str,emb)) + '\n')
        fw0.close()
        fw1.close()

这里介绍几个知识点:

  1. sparse.coo_matrix()
    将此矩阵转换为压缩稀疏行格式,重复的条目将汇总在一起
    参考
  2. bm25_weight
    其实我们可以用numpy或者是自己写公式完成矩阵分解的过程,但是会比较慢,这里提供一个比较快的方法就是利用implicit库中的bm25算法
    参考

lightfm

from lightfm import LightFM
from lightfm.data import Dataset

def train_model():
        global mid_list, docid_list, score_list, dataset, _id_user_mapping, _id_item_mapping, model
        dataset = Dataset()
        dataset.fit(users=np.unique(mid_list), items=np.unique(docid_list))
        print 'len(dataset._user_id_mapping):', len(dataset._user_id_mapping)
        print 'len(dataset._item_id_mapping):', len(dataset._item_id_mapping) 
        _id_user_mapping = {v: k for k, v in dataset._user_id_mapping.items()}
        _id_item_mapping = {v: k for k, v in dataset._item_id_mapping.items()}
    
        train_interactions, train_weights = dataset.build_interactions((mid_list[i], docid_list[i], score_list[i]) for i in range(len(score_list)))
        model = LightFM(no_components=100, loss='warp')
        print 'model.fit start ...'
        model.fit(interactions=train_interactions, sample_weight=train_weights, epochs=my_epochs, num_threads=20, verbose=True)
        print 'model.fit end ...'
  
        item_biased, item_representations = model.get_item_representations()
        print item_biased.shape
        #print item_biased
        print item_representations.shape
        #print item_representations
    
        user_biases, user_embeddings = model.get_user_representations()
        print user_biases.shape
        #print user_biases
        print user_embeddings.shape
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实例:电影推荐系统 描述:电影推荐系统是一种利用用户历史评分数据,为用户推荐未评分电影的系统。其中,用户历史评分数据可以表示成一个矩阵R,其中行表示用户,列表示电影,元素表示用户对电影的评分。电影推荐系统的目标是预测用户未评分电影的评分,并为用户推荐评分较高的电影。 转化:电影推荐系统可以转化为矩阵分解问题。假设用户历史评分数据矩阵R可以分解为两个较小的矩阵P和Q的乘积,其中P是用户的特征矩阵,Q是电影的特征矩阵。其中,P的行表示用户,列表示用户的特征,Q的行表示电影,列表示电影的特征。特征矩阵中的元素表示用户或电影在该特征上的权重,特征数目可以根据实际情况设定。 设R的第i行第j列元素为$R_{i,j}$,则有: $$R\approx P\times Q^T=\sum_{k=1}^{K}P_{i,k}\times Q_{j,k}$$ 其中,K为特征数目。 为了使得矩阵分解更加准确,我们需要最小化预测评分与真实评分的误差。设R中已知评分的位置为$I$,预测评分为$\hat{R}$,则最小化误差的目标函数为: $$\min_{P,Q}\sum_{(i,j)\in I}(R_{i,j}-\hat{R}_{i,j})^2$$ 使用梯度下降等优化算法,可以求解目标函数的最小值,得到特征矩阵P和Q,从而预测用户未评分电影的评分。 实现:以下是用matlab实现电影推荐系统的代码。 ```matlab % 读入电影评分数据 data = load('ratings.dat'); % 按照一定比例划分为训练集和测试集 [train_data, test_data] = split_data(data, 0.8); % 设置特征数目 K = 10; % 初始化特征矩阵P和Q P = rand(size(train_data,1), K); Q = rand(size(train_data,2), K); % 设置学习率和正则化参数 alpha = 0.01; beta = 0.1; % 迭代求解特征矩阵 for step = 1:1000 % 随机梯度下降更新P和Q for i = 1:size(train_data,1) for j = 1:size(train_data,2) if train_data(i,j) ~= 0 eij = train_data(i,j) - P(i,:)*Q(j,:)'; P(i,:) = P(i,:) + alpha*(eij*Q(j,:) - beta*P(i,:)); Q(j,:) = Q(j,:) + alpha*(eij*P(i,:) - beta*Q(j,:)); end end end % 计算目标函数的误差 e = 0; for i = 1:size(test_data,1) for j = 1:size(test_data,2) if test_data(i,j) ~= 0 e = e + (test_data(i,j) - P(i,:)*Q(j,:)')^2; for k = 1:K e = e + beta/2*(P(i,k)^2 + Q(j,k)^2); end end end end % 如果误差已经足够小,则退出迭代 if e < 0.001 break; end end % 预测用户未评分电影的评分 pred_data = P*Q'; ``` 分析:电影推荐系统是一个典型的矩阵分解应用,通过矩阵分解可以将高维度的评分数据降到低维度的特征矩阵中,从而提高预测准确率。在实现过程中,需要注意优化算法的选择和参数的调节,以及训练集和测试集的划分,以保证推荐系统的准确性和泛化能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值