1.引言
  假如你经营着一家网店,里面卖各种商品(Items),有很多用户在你的店里面买过东西,并对买过的Items进行了评分,我们称之为历史信息,现在为了提高销售量,必须主动向用户推销产品,所以关键是要判断出用户除了已经买过的商品之外还会喜欢哪些商品,这需要利用用户购买商品过程产生的历史信息。协同过滤通常分为基于用户的协同过滤和基于商品的协同过滤。
  基于用户的协同过滤:利用用户之间的相似度进行推荐
  基于物品的协同过滤:利用物品之间的相似度进行推荐
  2.原理
  关于协同过滤的原理网上到处都有,思想很简单,这里不赘述,下面举一个简单的实例来说明基于用户的协同过滤:

  上面每一行代表一个用户,每一列代表一个商品,比如第2行第一列的3表示用户2对商品1的评分为3,0代表对应的用户还没有购买过该商品,现在想预测用户2对商品4的评分:
  找出对商品4评过分的用户:用户1,3,5,8,9,10,评分分别为:4, 2, 1, 3, 3, 1
  分别计算用户2与用户1,3,5,8,9,10之间的相似度,相似度的计算方法有很多,常用的分为3类:欧氏距离,余弦相似度,皮尔逊相关系数,网上很容易查到,这里以常用的余弦相关系数说明:
  要计算用户2与用户1之间的相似度,首先找到二者都评过分的商品为:商品1, 2, 9, 10,用户1对这4个商品的评分向量为r1=[5 3 4 4],用户2对这4个商品评分向量为r2=[3 1 1 2];所谓余弦相似度是利用两个向量之间夹角的余弦值来衡量两个向量之间的相似度,显然夹角越小,余弦值越大,两个向量越靠近,即二者越相似,于是用户2和用户1之间的相似度为sim2_1=(5*3 + 3*1 + 4*1 + 4*2)/ (||r1|| * ||r2||) = 0.953, 其中||r||代表向量r的模长或者2范数,类似地分别计算出用户2与用户3 5 8 9 10之间的sim2_3,sim2_5,sim2_8,sim2_9,sim2_10
  后利用相似度加权得到用户2对商品4的预测评分:predict = 4*sim2_1 + 2*sim2_3 + 1*sim2_5 + 3*sim2_8 + 3*sim2_9 + 1*sim2_10
  基于物品相似度是与上面计算过程几乎相似,只是计算的是物品之间的相似度
  3.实现
  关于Matlab的实现可以参考:http://blog.csdn.net/google19890102/article/details/28112091,这里我用C++实现,并用movielens.rar进行测试,这个数据集是包括训练集和测试集,已经处理成矩阵形式。
  首先给出读取训练数据和保存预测结果的头文件

 

#ifndef LOAD_H
#define LOAD_H
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
template <typename T>
vector<vector<T> > txtRead(string FilePath,int row,int col)
{
ifstream input(FilePath);
if (!input.is_open())
{
cerr << "File is not existing, check the path: " <<  FilePath << endl;
exit(1);
}
vector<vector<T> > data(row, vector<T>(col,0));
for (int i = 0; i < row; ++i)
{
for (int j = 0; j < col; ++j)
{
input >> data[i][j];
}
}
return data;
}
template<typename T>
void txtWrite(vector<vector<T> > Matrix, string dest)
{
ofstream output(dest);
vector<vector<T> >::size_type row = Matrix.size();
vector<T>::size_type col = Matrix[0].size();
for (vector<vector<T> >::size_type i = 0; i < row; ++i)
{
for (vector<T>::size_type j = 0; j < col; ++j)
{
output << Matrix[i][j];
}
output << endl;
}
}
#endif

  再给出评价预测好坏的计算RMSE的头文件