协同过滤推荐算法

系统 1616 0

转载自:http://www.cnblogs.com/zhangchaoyang/articles/2631907.html

Collaborative Filtering Recommendation

向量之间的相似度

度量向量之间的相似度方法很多了,你可以用距离(各种距离)的倒数,向量夹角,Pearson相关系数等。

皮尔森相关系数计算公式如下:

分子是协方差,分子是两个变量标准差的乘积。显然要求X和Y的标准差都不能为0。

因为 ,所以皮尔森相关系数计算公式还可以写成:

当两个变量的线性关系增强时,相关系数趋于1或-1。

用户评分预测

用户评分预测的基本原理是:

step1. 如果用户i对项目j没有评过分,就找到与用户i最相似的K个邻居(使用向量相似度度量方法)

step2. 然后用这K个邻居对项目j的评分的加权平均来预测用户i对项目j的评分。

iterm 1 ………… item n
user 1 R 11 R 1n
…… R ij
user m R m1 R mn

用户评分数据矩阵

step1.

用户评分矩阵是个高度稀疏的矩阵,即用户对很多项目都没有评分。在高度稀疏的情况下用传统的向量相似度度量方法来度量两个用户的相似度就会很不准确。一种简单的处理办法是对未评分的项都令其等于该用户的平均评分值。

度量用户i和用户j相似度更好的方法是:

1.用户i参与评分的项目集合为I i ,用户i参与评分的项目集合为I j ,找到它们的并集

2.在集合 中用户i未评分的项目是 ,重新估计用户i对 中每个项目的评分

  2.1.取出评分矩阵的两列,计算这两列的相似度就是这两个项目的相似度。 。找到与 最相似的V个项目构成集合

  2.2.

3.这样用户i和j对 的评分就都是非0值了,在此情况下计算他们的相似度。

step2.

表示用户u对所有评分过的项目的评分平均值。

完了,可以看到算法非常的简单,核心就是计算向量的相似度。代码量也很少。

      #include<iostream>
      
        
#include
      
      <queue>
      
        
#include
      
      <cmath>
      
        
#include
      
      <cassert>
      
        
#include
      
      <cstdlib>
      
        
#include
      
      <fstream>
      
        
#include
      
      <sstream>
      
        
#include
      
      <vector>
      
        
#include
      
      <algorithm>


      
        using
      
      
        namespace
      
      
         std;


      
      
        const
      
      
        int
      
       ITERM_SIZE=
      
        1682
      
      
        ;

      
      
        const
      
      
        int
      
       USER_SIZE=
      
        943
      
      
        ;

      
      
        const
      
      
        int
      
       V=
      
        15
      
      ;        
      
        //
      
      
        ITERM的最近邻居数
      
      
        const
      
      
        int
      
       S=
      
        10
      
      ;        
      
        //
      
      
        USER的最近邻居数
      
      
        struct
      
      
         MyPair{
    
      
      
        int
      
      
         id;
    
      
      
        double
      
      
         value;
    MyPair(
      
      
        int
      
       i=
      
        0
      
      ,
      
        double
      
       v=
      
        0
      
      
        ):id(i),value(v){}
};


      
      
        struct
      
      
         cmp{
    
      
      
        bool
      
      
        operator
      
      () (
      
        const
      
       MyPair & obj1,
      
        const
      
       MyPair & obj2)
      
        const
      
      
        {
        
      
      
        return
      
       obj1.value <
      
         obj2.value;
    }
};


      
      
        double
      
       rate[USER_SIZE][ITERM_SIZE];    
      
        //
      
      
        评分矩阵
      
      
MyPair nbi[ITERM_SIZE][V];            
      
        //
      
      
        存放每个ITERM的最近邻居
      
      
MyPair nbu[USER_SIZE][S];            
      
        //
      
      
        存放每个USER的最近邻居
      
      
        double
      
       rate_avg[USER_SIZE];            
      
        //
      
      
        每个用户的平均评分


      
      
        //
      
      
        从文件中读入评分矩阵
      
      
        int
      
       readRate(
      
        string
      
      
         filename){
    ifstream ifs;
    ifs.open(filename.c_str());
    
      
      
        if
      
      (!
      
        ifs){
        cerr
      
      <<
      
        "
      
      
        error:unable to open input file 
      
      
        "
      
      <<filename<<
      
        endl;
        
      
      
        return
      
       -
      
        1
      
      
        ;
    }
    
      
      
        string
      
      
         line;
    
      
      
        while
      
      
        (getline(ifs,line)){
        
      
      
        string
      
      
         str1,str2,str3;
        istringstream strstm(line);
        strstm
      
      >>str1>>str2>>
      
        str3;
        
      
      
        int
      
       userid=
      
        atoi(str1.c_str());
        
      
      
        int
      
       itermid=
      
        atoi(str2.c_str());
        
      
      
        double
      
       rating=
      
        atof(str3.c_str());
        rate[userid
      
      -
      
        1
      
      ][itermid-
      
        1
      
      ]=
      
        rating;
        line.clear();
    }
    ifs.close();
    
      
      
        return
      
      
        0
      
      
        ;
}


      
      
        //
      
      
        计算每个用户的平均评分
      
      
        void
      
      
         getAvgRate(){
    
      
      
        for
      
      (
      
        int
      
       i=
      
        0
      
      ;i<USER_SIZE;++
      
        i){
        
      
      
        double
      
       sum=
      
        0
      
      
        ;
        
      
      
        for
      
      (
      
        int
      
       j=
      
        0
      
      ;j<ITERM_SIZE;++
      
        j)
            sum
      
      +=
      
        rate[i][j];
        rate_avg[i]
      
      =sum/
      
        ITERM_SIZE;
    }
}


      
      
        //
      
      
        计算两个向量的皮尔森相关系数
      
      
        double
      
       getSim(
      
        const
      
       vector<
      
        double
      
      > &vec1,
      
        const
      
       vector<
      
        double
      
      > &
      
        vec2){
    
      
      
        int
      
       len=
      
        vec1.size();
    assert(len
      
      ==
      
        vec2.size());
    
      
      
        double
      
       sum1=
      
        0
      
      
        ;
    
      
      
        double
      
       sum2=
      
        0
      
      
        ;
    
      
      
        double
      
       sum1_1=
      
        0
      
      
        ;
    
      
      
        double
      
       sum2_2=
      
        0
      
      
        ;
    
      
      
        double
      
       sum=
      
        0
      
      
        ;
    
      
      
        for
      
      (
      
        int
      
       i=
      
        0
      
      ;i<len;i++
      
        ){
        sum
      
      +=vec1[i]*
      
        vec2[i];
        sum1
      
      +=
      
        vec1[i];
        sum2
      
      +=
      
        vec2[i];
        sum1_1
      
      +=vec1[i]*
      
        vec1[i];
        sum2_2
      
      +=vec2[i]*
      
        vec2[i];
    }
    
      
      
        double
      
       ex=sum1/
      
        len;
    
      
      
        double
      
       ey=sum2/
      
        len;
    
      
      
        double
      
       ex2=sum1_1/
      
        len;
    
      
      
        double
      
       ey2=sum2_2/
      
        len;
    
      
      
        double
      
       exy=sum/
      
        len;
    
      
      
        double
      
       sdx=sqrt(ex2-ex*
      
        ex);
    
      
      
        double
      
       sdy=sqrt(ey2-ey*
      
        ey);
    assert(sdx
      
      !=
      
        0
      
       && sdy!=
      
        0
      
      
        );
    
      
      
        double
      
       sim=(exy-ex*ey)/(sdx*
      
        sdy);
    
      
      
        return
      
      
         sim;
}


      
      
        //
      
      
        计算每个ITERM的最近邻
      
      
        void
      
      
         getNBI(){
    
      
      
        for
      
      (
      
        int
      
       i=
      
        0
      
      ;i<ITERM_SIZE;++
      
        i){
        vector
      
      <
      
        double
      
      >
      
         vec1;
        priority_queue
      
      <MyPair,vector<MyPair>,cmp>
      
         neighbour;
        
      
      
        for
      
      (
      
        int
      
       k=
      
        0
      
      ;k<USER_SIZE;k++
      
        )
            vec1.push_back(rate[k][i]);
        
      
      
        for
      
      (
      
        int
      
       j=
      
        0
      
      ;j<ITERM_SIZE;j++
      
        ){
            
      
      
        if
      
      (i==
      
        j)
                
      
      
        continue
      
      
        ;
            vector
      
      <
      
        double
      
      >
      
         vec2;
            
      
      
        for
      
      (
      
        int
      
       k=
      
        0
      
      ;k<USER_SIZE;k++
      
        )
                vec2.push_back(rate[k][j]);
            
      
      
        double
      
       sim=
      
        getSim(vec1,vec2);
            MyPair p(j,sim);
            neighbour.push(p);
        }
        
      
      
        for
      
      (
      
        int
      
       j=
      
        0
      
      ;j<V;++
      
        j){
            nbi[i][j]
      
      =
      
        neighbour.top();
            neighbour.pop();
        }
    }
}


      
      
        //
      
      
        预测用户对未评分项目的评分值
      
      
        double
      
       getPredict(
      
        const
      
       vector<
      
        double
      
      > &user,
      
        int
      
      
         index){
    
      
      
        double
      
       sum1=
      
        0
      
      
        ;
    
      
      
        double
      
       sum2=
      
        0
      
      
        ;
    
      
      
        for
      
      (
      
        int
      
       i=
      
        0
      
      ;i<V;++
      
        i){
        
      
      
        int
      
       neib_index=
      
        nbi[index][i].id;
        
      
      
        double
      
       neib_sim=
      
        nbi[index][i].value;
        sum1
      
      +=neib_sim*
      
        user[neib_index];
        sum2
      
      +=
      
        fabs(neib_sim);
    }
    
      
      
        return
      
       sum1/
      
        sum2;
}


      
      
        //
      
      
        计算两个用户的相似度
      
      
        double
      
       getUserSim(
      
        const
      
       vector<
      
        double
      
      > &user1,
      
        const
      
       vector<
      
        double
      
      > &
      
        user2){
    vector
      
      <
      
        double
      
      >
      
         vec1;
    vector
      
      <
      
        double
      
      >
      
         vec2;
    
      
      
        int
      
       len=
      
        user1.size();
    assert(len
      
      ==
      
        user2.size());
    
      
      
        for
      
      (
      
        int
      
       i=
      
        0
      
      ;i<len;++
      
        i){
        
      
      
        if
      
      (user1[i]!=
      
        0
      
       || user2[i]!=
      
        0
      
      
        ){
            
      
      
        if
      
      (user1[i]!=
      
        0
      
      
        )
                vec1.push_back(user1[i]);
            
      
      
        else
      
      
        
                vec1.push_back(getPredict(user1,i));
            
      
      
        if
      
      (user2[i]!=
      
        0
      
      
        )
                vec2.push_back(user2[i]);
            
      
      
        else
      
      
        
                vec2.push_back(getPredict(user2,i));
        }
    }
    
      
      
        return
      
      
         getSim(vec1,vec2);
}


      
      
        //
      
      
        计算每个USER的最近邻
      
      
        void
      
      
         getNBU(){
    
      
      
        for
      
      (
      
        int
      
       i=
      
        0
      
      ;i<USER_SIZE;++
      
        i){
        vector
      
      <
      
        double
      
      >
      
         user1;
        priority_queue
      
      <MyPair,vector<MyPair>,cmp>
      
         neighbour;
        
      
      
        for
      
      (
      
        int
      
       k=
      
        0
      
      ;k<ITERM_SIZE;++
      
        k)
            user1.push_back(rate[i][k]);
        
      
      
        for
      
      (
      
        int
      
       j=
      
        0
      
      ;j<USER_SIZE;++
      
        j){
            
      
      
        if
      
      (j==
      
        i)
                
      
      
        continue
      
      
        ;
            vector
      
      <
      
        double
      
      >
      
         user2;
            
      
      
        for
      
      (
      
        int
      
       k=
      
        0
      
      ;k<ITERM_SIZE;++
      
        k)
                user2.push_back(rate[j][k]);
            
      
      
        double
      
       sim=
      
        getUserSim(user1,user2);
            MyPair p(j,sim);
            neighbour.push(p);
        }
        
      
      
        for
      
      (
      
        int
      
       j=
      
        0
      
      ;j<S;++
      
        j){
            nbu[i][j]
      
      =
      
        neighbour.top();
            neighbour.pop();
        }
    }
}
            

      
      
        //
      
      
        产生推荐,预测某用户对某项目的评分
      
      
        double
      
       predictRate(
      
        int
      
       user,
      
        int
      
      
         iterm){
    
      
      
        double
      
       sum1=
      
        0
      
      
        ;
    
      
      
        double
      
       sum2=
      
        0
      
      
        ;
    
      
      
        for
      
      (
      
        int
      
       i=
      
        0
      
      ;i<S;++
      
        i){
        
      
      
        int
      
       neib_index=
      
        nbu[user][i].id;
        
      
      
        double
      
       neib_sim=
      
        nbu[user][i].value;
        sum1
      
      +=neib_sim*(rate[neib_index][iterm]-
      
        rate_avg[neib_index]);
        sum2
      
      +=
      
        fabs(neib_sim);
    }
    
      
      
        return
      
       rate_avg[user]+sum1/
      
        sum2;
}


      
      
        //
      
      
        测试
      
      
        int
      
      
         main(){
    
      
      
        string
      
       file=
      
        "
      
      
        /home/orisun/DataSet/movie-lens-100k/u.data
      
      
        "
      
      
        ;
    
      
      
        if
      
      (readRate(file)!=
      
        0
      
      
        ){
        
      
      
        return
      
       -
      
        1
      
      
        ;
    }
    getAvgRate();
    getNBI();
    getNBU();
    
      
      
        while
      
      (
      
        1
      
      
        ){
        cout
      
      <<
      
        "
      
      
        please input user index and iterm index which you want predict
      
      
        "
      
      <<
      
        endl;
        
      
      
        int
      
      
         user,iterm;
        cin
      
      >>user>>
      
        iterm;
        cout
      
      <<predictRate(user,iterm)<<
      
        endl;
    }
    
      
      
        return
      
      
        0
      
      
        ;
}
      
    

协同过滤推荐算法


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论