推荐算法:基于领域的协同过滤

2019-06-02  本文已影响0人  张虾米试错

大纲

  1. user-based cf
  2. item-based cf
  3. item_based 代码实践
  4. user_based vs. item_based

1.user_based cf

基于用户的协同过滤算法的思路是:找到与该用户有相似兴趣的用户,然后将这些相似用户感兴趣的商品推荐给该用户。因此,基于用户协同过滤算法可以分为2个步骤:

1.1 用户相似度的改进

用余弦相似度来度量用户之间兴趣相似度过于粗糙,因为两个用户对热门物品采取过相同的行为并不能说明他们兴趣相似,但对于冷门物品才去过相同的行为更能说明他们兴趣的相似度。
sim_{uv} =\frac{ \sum_{i \in N(u) \bigcap N(v)}\frac{1}{\log (1+|N(i)|)}}{\sqrt{|N(u)| \space |N(v)|}}

2.item_based cf

基于物品的协同过滤算法直接找出目标用户感兴趣的商品,然后将和这些商品相似的商品推荐给目标用户。物品相似度也是通过Jaccard或者余弦相似度来衡量,这里不再赘述。因此,基于物品的推荐的2个步骤:

3. item_based 代码实践

代码中有些地方用numpy代替dict,可以降低内存,不过仍然有个问题,因为item之间的相似关系可能是稀疏的,但是numpy是密集型,所以也存在空间浪费。
由于user-based和item-based原理一样,因此下面只展示了item-based的代码实践。

item-based cf

# -*- coding:utf-8 -*-
import pandas as pd
import numpy as np
import math
import json


class ItemCF(object):
    def __init__(self, fname):
        self.fname = fname
        self._read_data1(fname)
        
    def _read_data(self, fname):
        self.item_users = {}
        with open(fname, "r") as fr:
            for line in fr:
                fields = line.strip().split(",")
                device_uid = fields[1]
                resblock_id = fields[2]
                cnt = fields[3]
                self.item_users.setdefault(resblock_id, {})
                self.item_users[resblock_id][device_uid] = cnt
        # 对物品编号
        all_items = self.item_users.keys()
        self.item_size = len(all_items)
        self.item_vocab = dict([(item, ind) for ind, item in enumerate(all_items)])
        self.item_reverse_vocab = np.array(all_items)
    
    def similarity(self):
        self.item_popularity = np.zeros(self.item_size)
        # 计算浏览物品的用户数
        for item, user_info in self.item_users.items():
            _item_index = self.item_vocab[item]
            self.item_popularity[_item_index] = len(user_info)
        # 计算物品相似度
        self.item_similarity = np.zeros((self.item_size, self.item_size))
        for i in range(self.item_size-1):
            _former_item = self.item_reverse_vocab[i]
            _former_item_popularity = self.item_popularity[i]
            _former_item_users = self.item_users[_former_item].keys()
            for j in range(i+1, self.item_size):
                _latter_item = self.item_reverse_vocab[j]
                _latter_item_popularity = self.item_popularity[j]
                _latter_item_users = self.item_users[_latter_item].keys()
                common_size = len(set(_former_item_users) & set(_latter_item_users))
                sim = float(common_size) / math.sqrt(_former_item_popularity * _latter_item_popularity)
                self.item_similarity[i][j] = sim
                self.item_similarity[j][i] = sim
                
    def save_model(self, vocab_reverse_fname, sim_fname):
        np.save(vocab_reverse_fname, self.item_reverse_vocab)
        np.save(sim_fname, self.item_similarity)

4.user_based vs. item_based

对比项 user_based item_based
性能 适合于用户数量较小的场景 适用于物品数量明显小于用户数量的场景
个性化 时效性较强,用户个性化兴趣不太明显的领域 长尾物品丰富,用户个性化需求强烈的领域
实时性 用户的新行为不一定导致推荐结果的立即变化 用户的新行为一定会导致推荐结果的实时变化

参考文献

上一篇下一篇

猜你喜欢

热点阅读