java和python实现一个加权SlopeOne推荐算法

一.加权SlopeOne算法公式:

(1).求得所有item之间的评分偏差

上式中分子部分为项目j与项目i的偏差和,分母部分为所有同时对项目j与项目i评分的用户数

(2).加权预测评分

项目j与项目i

上式中表示用户u对项目j的评分预测,分子为项目j对项目i的偏差加上用户对项目i的评分,cji表示同时对项目j与项目i评分的用户数

二.python实现

#!/usr/bin/python
# -*- coding: utf-8 -*-

user_data = {"小明": {"张学友": 4, "周杰伦": 3, "刘德华": 4},
          "小海": {"张学友": 5, "周杰伦": 2},
          "李梅": {"周杰伦": 3.5, "刘德华": 4},
          "李磊": {"张学友": 5, "刘德华": 3}}

class recommender:

    def __init__(self,data):
        self.frequency={}
        self.deviation={}
        self.data=data

    #计算所有item之间评分偏差
    def computeDeviation(self):
        for ratings in self.data.values():
            for item,rating in ratings.items():
                self.frequency.setdefault(item,{})
                self.deviation.setdefault(item,{})
                for item2,rating2 in ratings.items():
                    if item!=item2:
                        self.frequency[item].setdefault(item2,0)
                        self.deviation[item].setdefault(item2,0.0)
                        self.frequency[item][item2]+=1#两个项目的用户数
                        self.deviation[item][item2]+=(rating-rating2)#累加两个评分差值
        for item,ratings in self.deviation.items():
            for item2 in ratings:
                ratings[item2]/=self.frequency[item][item2]

    #评分预测
    def predictRating(self,userRatings,k):
        recommendations={}
        frequencies={}
        for item,rating in userRatings.items():
            for diffItem,diffRating in self.deviation.items():
                if diffItem not in userRatings and item in self.deviation[diffItem]:
                    fre=self.frequency[diffItem][item]
                    recommendations.setdefault(diffItem,0.0)
                    frequencies.setdefault(diffItem,0)
                    #分子部分
                    recommendations[diffItem]+=(diffRating[item]+rating)*fre
                    #分母部分
                    frequencies[diffItem]+=fre
        recommendations=[(k,v/frequencies[k]) for (k,v) in recommendations.items()]
        #排序返回前k个
        recommendations.sort(key=lambda a_tuple:a_tuple[1],reverse=True)
        return recommendations[:k]

if __name__=='__main__':
    r=recommender(user_data)
    r.computeDeviation()
    u=user_data['李磊']
    print(r.predictRating(u,5))

三.java实现

import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Collections;

/**
 * Created by  on 2016/12/8.ShiYan
 * 一.计算所有物品对的偏差
 * 二.利用偏差进行预测
 */
public class SlopeOne {
    Map<String,Map<String,Integer>> frequency=null;
    Map<String,Map<String,Double>> deviation=null;
    Map<String,Map<String,Integer>> user_rating=null;

    public SlopeOne( Map<String,Map<String,Integer>> user_rating){
        frequency=new HashMap<String,Map<String,Integer>>();
        deviation=new HashMap<String,Map<String,Double>>();
        this.user_rating=user_rating;
    }

    /**
     * 所有有item间的评分偏差
     */
    public void computeDeviation(){
        for(Map.Entry<String,Map<String,Integer>> ratingsEntry:user_rating.entrySet()){
            for(Map.Entry<String,Integer> ratingEntry:ratingsEntry.getValue().entrySet()){
                String item=ratingEntry.getKey();
                int rating=ratingEntry.getValue();
                Map<String,Integer> itemFrequency=null;
                if(!frequency.containsKey(item)){
                    itemFrequency=new HashMap<String, Integer>();
                    frequency.put(item,itemFrequency);
                }else{
                    itemFrequency=frequency.get(item);
                }

                Map<String,Double> itemDeviation=null;
                if(!deviation.containsKey(item)){
                    itemDeviation=new HashMap<String, Double>();
                    deviation.put(item,itemDeviation);
                }else{
                    itemDeviation=deviation.get(item);
                }

                for(Map.Entry<String,Integer> ratingEntry2:ratingsEntry.getValue().entrySet()){
                    String item2=ratingEntry2.getKey();
                    int rating2=ratingEntry2.getValue();
                    if(!item.equals(item2)){
                        //两个项目的用户数
                        itemFrequency.put(item2,itemFrequency.containsKey(item2)?itemFrequency.get(item2)+1:0);
                        //两个项目的评分偏差,累加
                        itemDeviation.put(item2,itemDeviation.containsKey(item2)?itemDeviation.get(item2)+(rating-rating2):0.0);
                    }
                }
            }
        }

        for(Map.Entry<String,Map<String,Double>> itemsDeviation:deviation.entrySet()){
            String item=itemsDeviation.getKey();
            Map<String,Double> itemDev=itemsDeviation.getValue();
            Map<String,Integer> itemFre=frequency.get(item);
            for(String itemName:itemDev.keySet()){
                itemDev.put(itemName,itemDev.get(itemName)/itemFre.get(itemName));
            }
        }
    }

    /**
     * 评分预测
     * @param userRating 目标用户的评分
     * @param k 返回前k个
     * @return
     */
    public  List<Map.Entry<String,Double>> predictRating(Map<String,Integer> userRating,int k){
        Map<String,Double> recommendations=new HashMap<String,Double>();
        Map<String,Integer> frequencies=new HashMap<String, Integer>();
        for(Map.Entry<String,Integer> userEntry:userRating.entrySet()){
            String userItem=userEntry.getKey();
            double rating=userEntry.getValue();
            for(Map.Entry<String,Map<String,Double>> deviationEntry:deviation.entrySet()){
                String item=deviationEntry.getKey();
                Map<String,Double> itemDeviation=deviationEntry.getValue();
                Map<String,Integer> itemFrequency=frequency.get(item);
                if(!userRating.containsKey(item) && itemDeviation.containsKey(userItem)){
                    int fre=itemFrequency.get(userItem);
                    if(!recommendations.containsKey(item))
                        recommendations.put(item,0.0);
                    if(!frequencies.containsKey(item))
                        frequencies.put(item,0);
                    //分子部分
                    recommendations.put(item,recommendations.get(item)+(itemDeviation.get(userItem)+rating)*fre);
                    //分母部分
                    frequencies.put(item,frequencies.get(item)+fre);
                }
            }
        }
        for(Map.Entry<String,Double> recoEntry:recommendations.entrySet()){
            String key=recoEntry.getKey();
            double value=recoEntry.getValue()/frequencies.get(key);
            recommendations.put(key,value);
        }
        //排序,这里还可以使用优先队列返回top_k
        List<Map.Entry<String,Double>> list_map=new ArrayList<Map.Entry<String,Double>>(recommendations.entrySet());
        Collections.sort(list_map,new Comparator<Map.Entry<String,Double>>(){
                    @Override
                    public int compare(Map.Entry<String, Double> o1, Map.Entry<String, Double> o2) {
                        if(o2.getValue()>o1.getValue())
                            return 1;
                        else if(o2.getValue()<o1.getValue())
                            return -1;
                        else
                            return 0;
                    }
                }
        );
        List<Map.Entry<String,Double>> top_k=new ArrayList<Map.Entry<String, Double>>();
        if(list_map.size()<k) k=list_map.size();
        for(int i=0;i<k;i++){
            top_k.add(list_map.get(i));
        }
        return top_k;
    }

    public static void main(String[] args){
        Map<String,Map<String,Integer>> userRatings=new HashMap<String, Map<String, Integer>>();
        Map<String,Integer> xiMingRating=new HashMap<String, Integer>();
        xiMingRating.put("张学友",4);
        xiMingRating.put("周杰伦",3);
        xiMingRating.put("刘德华",4);
        Map<String,Integer> xiHaiRating=new HashMap<String, Integer>();
        xiHaiRating.put("张学友",5);
        xiHaiRating.put("周杰伦",2);
        Map<String,Integer> liMeiRating=new HashMap<String, Integer>();
        liMeiRating.put("周杰伦",3);
        liMeiRating.put( "刘德华",4);
        Map<String,Integer> liLeiRating=new HashMap<String, Integer>();
        liLeiRating.put("张学友",5);
        liLeiRating.put("刘德华",3);
        userRatings.put("xiMing",xiMingRating);
        userRatings.put("xiHai",xiHaiRating);
        userRatings.put("liMei", liMeiRating);
        userRatings.put("liLei",liLeiRating);

        SlopeOne slopOne=new SlopeOne(userRatings);
        slopOne.computeDeviation();
        List<Map.Entry<String,Double>> top_k=slopOne.predictRating(userRatings.get("liLei"),5);
        for(Map.Entry<String,Double> item:top_k){
            System.out.println(item.getKey()+"   "+item.getValue());
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值