推薦算法—Slope One

 

1、計算平均誤差

u - user,用戶 html

i,j - 商品ios

u(i,j) - 同時評價過i,j商品的用戶集合測試

card - 數目spa

R(u,j) - 用戶u對商品j的評分3d

 

2、基礎Slope One

上述式子即爲獲得的評分誤差,接下來提出最簡單的slope one預測評分的式子。code

 

3、帶權重的Slope One

在計算用戶u對商品i進行評估時,用戶u對j,k進行過評分,j商品共有2000人同時也對i評分了,而k商品僅有200人,明顯使用j商品進行評估更合理,因此這裏使用了權重。xml

 

4、雙極性Slope One

先將用戶對某個物品的評分分爲like,dislike兩類。經過評分是否大於該用戶本身的平均評分。htm

相似地,能夠定義對item ii 和 jj 具備相同喜愛的用戶集合blog

 

利用上面的定義,咱們可使用下面的公式爲(like或dislike的item)得到新的誤差值:字符串

這樣能夠計算從item ii 計算獲得的預測值:

最終 Bi-Polar Slope One 的預測公式爲:

 

參考: http://www.cnblogs.com/breezedeus/archive/2011/03/11/1981781.html

 

5、評測指標

這裏採用RMSE做爲評測指標。計算公式爲:

  或者 

 

 

C++實現(權重slope-one實現):

  1 #include<iostream>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<fstream>
  5 #include<vector>
  6 #include<cmath>
  7 #include<set>
  8 
  9 using namespace std;
 10 
 11 const int N = 7448;
 12 int userMax = 0;
 13 int itemMax = 0;
 14 int r[N][N]; //記錄評分 
 15 int user_t[N]; //記錄測試集的數據 
 16 int item_t[N];
 17 int rate_t[N];
 18 set<int> test; //記錄測試集行號 
 19 
 20 void getTest(int m,int n){ //獲得測試集的行號 
 21     while(test.size()<m){
 22         test.insert(rand()%n);
 23     }
 24 }
 25 
 26 vector<string> split(string str,string pattern)
 27 {
 28     string::size_type pos;
 29     vector<string> result;
 30     str+=pattern;//擴展字符串以方便操做
 31     int size=str.size();
 32 
 33     for(int i=0; i<size; i++)
 34     {
 35         pos=str.find(pattern,i);
 36         if(pos<size)
 37         {
 38             std::string s=str.substr(i,pos-i);
 39             result.push_back(s);
 40             i=pos+pattern.size()-1;
 41         }
 42     }
 43     return result;
 44 }
 45 
 46 int main()
 47 {
 48     ifstream data("train_small_2.txt");
 49     
 50     string buffer;
 51     vector<string> temp;
 52     
 53     getTest(N/5,N);
 54     memset(r,0,sizeof(r));
 55     
 56     int t = 0;
 57     while(!data.eof()){ //數據處理,將一份數據分紅訓練集與測試集 
 58         getline(data,buffer);
 59         temp = split(buffer," ");
 60         int i = atoi(temp[0].c_str());
 61         int j = atoi(temp[1].c_str());
 62         //cout << i << " " << j <<endl;
 63         if(test.find(t)!=test.end()){
 64             user_t[t] = i;
 65             item_t[t] = j;
 66             rate_t[t] = atoi(temp[2].c_str());
 67         }else{    
 68             if(i > userMax) userMax = i;
 69             if(j > itemMax) itemMax = j;
 70             r[i][j] = atoi(temp[2].c_str());
 71         }
 72         t++;
 73     }
 74     set<int>::iterator it = test.begin();
 75     double rmse = 0;
 76     int num = 0;
 77     for(;it!=test.end();it++){ // uesr_t item_t
 78         int t = *it;
 79         int count = 0;    
 80         int sum = 0;
 81         for(int i=1;i<=itemMax;i++){//對於user_t[t],找到他評價的全部商品 i
 82             if(r[user_t[t]][i]!=0){
 83                 int cnt = 0;
 84                 int dev = 0;
 85                 for(int j=1;j<=userMax;j++){//找到同時評價item[t]與i的用戶 
 86                     if(r[j][item_t[t]]!=0 && r[j][i]!=0){
 87                         dev += (-r[j][i]+r[j][item_t[t]]); //求出誤差和 
 88                         cnt++;
 89                     }
 90                 }
 91                 sum += (dev+r[user_t[t]][i]*cnt); //加上對應權重的初始值 
 92                 count += cnt; //算出參與計算的樣例總數 
 93             }
 94         }
 95         double ans = sum*1.0/count;
 96         if(ans>=0 && ans <=5){ //因爲樣例少會出現不能計算的樣例的狀況,排除這些 
 97             rmse += pow((ans - rate_t[t]),2);
 98             num++;
 99             cout << user_t[t] <<" "<< item_t[t] <<" "<< ans << endl;
100         }
101     }
102     rmse = sqrt(rmse/num);
103     cout << "RMSE:" << rmse << endl;
104 }

 

運行結果:

RMSE:0.995244

可能數據集小的緣由,獲得的效果很好..

相關文章
相關標籤/搜索