基于Apriori算法的购物网站商品推荐系统
目 录
一、 算法内容 3
Step 1 收集用户偏好 3
Step 2 对数据进行预处理 3
Step 3 计算相似度 4
Step 4 找邻居 5
Step 5 计算推荐 6
二、 预期结果 6
三、 对比和讨论 7
Step 5 计算推荐
Section A 基于用户的协同过滤(User CF)
通过前面的步骤,已找到了当前用户的相似用户。相似用户偏好的商品,该用户可能也会喜欢。
将其相似用户偏好度较高而当前用户偏好度低的商品推荐给当前用户。
Section B 基于项目的协同过滤(Item CF)
通过前面的步骤,已找到了各商品的关联商品。喜欢商品A的用户很可能也会喜欢商品A的关联商品。
若某用户对商品A的偏好度较高,则将该用户偏好度低的商品A的关联商品推荐给该用户。
Section C 两者结合
用User CF的方法和用Item CF的方法得到的推荐效果在不同的衡量指标下各有好坏。
每个用户都会有若干个感兴趣的领域。
横向来看,使用User CF的方法进行推荐的商品涵盖了用户感兴趣的各个领域,在推荐商品的整体多样性上,User CF要比Item CF高。
纵向来看,由于Item CF倾向于推荐关联商品,因此对于用户感兴趣的某一领域,使用Item CF能够让用户拥有更多的该领域商品的选择空间。在这一方面上,推荐效果要比User CF好。
两种方法各有利弊,互为补充。将两者结合起来,将得到更好的推荐效果。因此,采用分区混合的组合方式,将不同的推荐结果显示在购物网站页面上的不同区域,让用户得到更全面的推荐。
二、预期结果
该算法基于用户在此购物网站上的行为,并用数字化指标对用户行为进行衡量。通过一系列数据处理方法得到用户对商品的偏爱度,用户间的相似度和商品间的关联度,然后通过协同过滤算法对用户进行推荐。
该算法结合了基于用户的协同过滤算法和基于项目的协同过滤算法,能使推荐商品涵盖用户感兴趣的各个领域,同时在其感兴趣的领域中,也能对该领域的商品进行广泛的推荐,让用户拥有较大的选择空间。
该算法的推荐结果有如下几个特点:
在该购物网站上使用记录越多的用户,其推荐效果越好;
喜好越大众化的用户,其推荐效果越准确;
若用户的喜好易变,推荐效果会受到一定影响;
用户有时会填写虚假信息,而其年龄,性别等基本信息的失真不会对推荐效果造成影响;
三、对比和讨论
观察淘宝的“猜你喜欢”,大部分的推荐商品是平行推荐产生的结果。也就是说,我最近浏览了,收藏了或是购买了商品A,淘宝就会给我推荐一系列不同店铺的商品A。
除此之外,淘宝的推荐排序还有很多商业成分在里面,稍含百度“竞价排名”的意味。举个例子:假如我最近搜索了商品A,淘宝的推荐系统会根据商品本身加权多少,商家推广力度大小,进行推荐排序。推广力度的大小往往需要商家出钱来决定。淘宝呈现出的推荐商品以高购买量,高评分的商品为主;而新商家,小商家很难在淘宝上单纯依赖商品关联程度让用户查看到自己商品。
而我设计的算法不掺杂商业因素,只考虑广大用户在该网站上的使用记录,以此探究商品之间的关联程度,致力于探究出像“啤酒和尿布”这样的商品关联关系;此算法完全依照用户的的实践经验,致力于准确地抓住用户特质,找到与当前用户拥有相同喜好的用户,实现推荐。
此算法得到的推荐排名完全依赖于商品的关联度与用户的相似度。一切以相关性为主,从而能使长尾商品也能出现在用户的视野里。
淘宝的推荐系统较为复杂,它有反作弊模型,时间模型,卖家模型,人气模型等进行分析,它采用了多种推荐算法混合的机制,权衡各种算法的利弊进行优势互补,以此提高推荐准确度。而我的推荐算法较为简单,依赖的数据较少,存在以下优缺点:
优点:
数据采集方便
该算法所依赖的数据仅用户对商品的评分情况,收藏情况,加入购物车情况,购买情况和对商品的查看次数这五项。这五项数据采集起来十分方便,并且易于处理和分析,计算量较小。
帮用户发现未知好货
由于不存在“竞价排名”的情况,推荐排序完全依赖于广大用户的浏览,收藏和购买情况。因此,对于一些用户A并不知道的而其相似用户用户B喜爱的好货,用户A就能从系统推荐里发现该产品,从而能够将优质的长尾商品推荐给用户。
自动寻找所需商品
像“啤酒与尿布”的例子一样,通过分析广大用户的使用情况,该算法可以从用户经验里分析出用户接下来可能需要的产品,并向其进行推荐,用户不需要自己搜索就能从系统推荐里看到接下来要购买的商品。这不仅省时省力,又能让该购物平台看起来“智能化”。
不足:
对新用户推荐效果差
该推荐算法为个性化推荐算法,需要依赖用户的历史行为记录,大量的用户行为数据是该推荐算法的先决条件。对于新用户来说,他们历史记录缺少,难以对其设计令他们满意的个性化推荐,存在我们所说的“冷启动”问题。
对喜好特殊的用户推荐商品横向多样性低
对于喜好特殊的用户,与他们喜好相似用户少。在这种情况下,User CF 算法的推荐效果会比较差。而由于Item CF倾向于推荐关联商品,推荐的商品往往是同一领域的,不够广泛。因此,对于喜好特殊的用户来说,系统推荐的商品横向领域多样性就会比较低。
不存在时间模型
不同类型的商品,用户的使用周期是不同的。对于日用品、食品等快速消耗品来说,商品的周转周期短,用户会进行频繁的购买。此类商品的推荐会给用户带来较好的推荐效果。而对于家电、家具等耐用品来说,商品的使用周期较长,一次性投资较大,用户不会进行频繁购买。此类商品的推荐容易产生这种现象:用户现在已经完全不需要购买此类商品,但却得到了许多关于此类商品的推荐。对于用户来说,并没有起到有效的推荐效果。
因此,该简单算法有其优点也有其不足,仍需结合其他推荐算法(如基于人口统计学的推荐算法等)和数据模型(如时间模型,年龄模型,性别模型,商品类别模型等)进一步改进和优化。
%表格读取 数据处理
clear
[filename1,pathname]=uigetfile('*.csv','打开文件'); %选择文件
if pathname~=0
filename=strcat(pathname,filename1);
[data header]=xlsread(filename);
end
% data=csvread('SPdata.csv',[1 end],[0 2],[1 0 end 2])
AB=data;
ddno=1;
while ~isempty(AB)
[usitemhb,lb]=find(AB(:,1)==AB(1,1));
usitno=length(usitemhb);
for i=1:usitno
ii=usitemhb(i);
B(ddno,1)=AB(1,1);
B(ddno,i+1)=AB(ii,2);
end
AB(1:usitno,:)=[];
ddno=ddno+1;
end
IT=unique(data(:,2));
save('spdata.mat','IT','B');
clear
load spdata
ZZ=[NaN];
ZZ=[ZZ;B(:,1)];
userno=length(B(:,1));
IT=IT';
itemno=length(IT);
ZZ(1,2:1+itemno)=IT;
for a=1:userno
for b=2:length(B(1,:))
if B(a,b)
[aa,bb]=find(ZZ(1,:)==B(a,b));
ZZ(a,bb)=1;
end
end
end
save('spdata4.mat','ZZ');
clear
load spdata4
ZZ=ZZ(1:201,1:3001);
X=ZZ(2:end,2:end);
th=10; %判断是否为频繁项集的阈值
tth=10;
thconf=0.2;%最小置信度阈值
[m,n]=size(X);
%频繁项集通过xj记录
%xj{i}(j).element
%xj{i}(j).time
%其中i表示频繁i项集,j表示频繁i项集中的一个元素,element记录数据项,time记录数据项出现的次数
%寻找频繁1项集
k=0;
for i=1:n
nm1(i)=sum(X(:,i));
if nm1(i)>=th
k=k+1;
pf1(k)=ZZ(1,i+1);
pfxj(k).element=ZZ(1,i+1);
pfxj(k).time=nm1(i);
end
end
xj{1}=pfxj;
clear pfxj;
%生成频繁2项集的候选项
if k>0
l=0;
for i=1:k-1
for j=i+1:k
l=l+1;
pf{l}=[pf1(i),pf1(j)];
end
end
end
%判断频繁2项集
nm(1:l)=0; %记录每个候选项出现的次数
for i=1:m
for j=1:l
se=pf{j};
sei=find(ZZ(1,:)==se(1));%从物品编号到所在列
sej=find(ZZ(1,:)==se(2));
if (X(i,sei-1)==1)&(X(i,sej-1)==1)
nm(j)=nm(j)+1;
end
end
end
k=0;
%找出频繁2项集
for i=1:l
if nm(i)>=tth %这里为3
k=k+1;
candidate{k}=pf{i};%频繁的 候选集
pfxj(k).element=pf{i};%二维的集合 两个商品
pfxj(k).time=nm(i);%出现的次数
end
end
xj{2}=pfxj;%个二维集
clear pfxj;
%candidate为最终得到的频繁项集
disp('得到的频繁项集为:')
for i=1:length(candidate)
result=num2str(candidate{i});
disp(result)
end
disp('得到的关联规则为:')
%规则生成过程
BG=[];%存储结果的矩阵
nnnlen=length(xj{1,end});
for nnni=1:nnnlen
nnn(nnni)=xj{1,end}(1,nnni).time;
end
for j=1:length(candidate)
hx=candidate{j};
support=nnn/m; %计算支持度,nnn记录每个频繁项集的出现次数
le=length(hx);
subsetall=ziji(hx);%%生成每个频繁项集的所有非空、非全集子集,利用子集得到规则
for i=1:le-1
L=length(subsetall{i});
for kk=1:L
%取出一个子集,生成关联规则,并判断置信度
SS=subsetall{i}{kk};
mid1=xj{i};
ln=length(mid1);
for ki=1:ln
s=mid1(ki).element;
if sum(SS==s)==i
conf1=mid1(ki).time;
end
end
re=num2str(SS);
confidence=nnn(j)/conf1;%计算置信度
re2=num2str(setsub(hx,SS));
result=strcat(re,'=>',re2,' support :',num2str(support(j)),' confidence : ',num2str(confidence));
bg=[SS,setsub(hx,SS),support(j),confidence];
% bg=[re,re2,support(j),confidence];
BG=[BG;bg];
if (confidence>=thconf)
disp(result) %规则输出
end
end
end
end
%连接步,两个集合若满足连接条件,则进行连接,生成K-1项候选集
cand=[];
num=2;
k=length(candidate);
BGG=[];
BCG=[];
while( k>0)
le=length(candidate{1});
nl=0;
for i=1:k-1
for j=i+1:k
x1=candidate{i};
x2=candidate{j};
c = intersect(x1, x2);%求两个集合共同元素 交集
if (length(c)==le-1) & (sum(c==x1(1:le-1))==le-1)
houxuan=union(x1(1:le),x2(le));%求并集
%树剪枝,若一个候选项的某个K-1项子集为非频繁,则剪枝掉
sub_set=subset(houxuan);
%生成该候选项的所有K-1项子集
NN=length(sub_set);
%判断这些K-1项自己是否都为频繁的
r=1; M=0;
while(r & M<NN)
M=M+1;
r=in(sub_set{M},candidate);
end
if M==NN
nl=nl+1;
%候选k项集
cand{nl}=houxuan;
end
end
end
end
%记录每个候选k项集出现的次数
k=length(cand);
if k>0
nn(1:k)=0;
le=length(cand{1});
for i=1:m
for j=1:k
s=cand{j};
x=X(i,:);
sle=length(s);
for ssl=1:sle
ss(ssl)=find(ZZ(1,:)==s(ssl));%求得元素所在列坐标
end
ss=ss-ones(1,sle);%X与ZZ之间的列差
if sum(x(ss))==le
nn(j)=nn(j)+1;
end
end
end
end
%从候选集中找频繁项集
ll=0;
candmid=[];
for i=1:k
if nn(i)>=tth
ll=ll+1;
candmid{ll}=cand{i};
pfxj(ll).element=cand{i};
pfxj(ll).time=nn(i);
end
end
k=length(candmid);
if k>0
num=num+1;
xj{num}=pfxj;
clear pfxj;
candidate=candmid;
end
cand=[];
%candidate为最终得到的频繁项集
disp('得到的频繁项集为:')
for i=1:length(candidate)
result=num2str(candidate{i});
disp(result)
end
nnnlen=length(xj{1,end});
for nnni=1:nnnlen
nnn(nnni)=xj{1,end}(1,nnni).time;
end
disp('得到的关联规则为:')
%规则生成过程
for j=1:length(candidate)
hx=candidate{j};
support=nnn/m; %计算支持度,nnn记录每个频繁项集的出现次数
le=length(hx);
subsetall=ziji(hx);%%生成每个频繁项集的所有非空、非全集子集,利用子集得到规则
for i=1:le-1
L=length(subsetall{i});
for kk=1:L
%取出一个子集,生成关联规则,并判断置信度
SS=subsetall{i}{kk};
mid1=xj{i};
ln=length(mid1);
for ki=1:ln
s=mid1(ki).element;
if sum(SS==s)==i
conf1=mid1(ki).time;
end
end
re=num2str(SS);
confidence=nnn(j)/conf1;%计算置信度
re2=num2str(setsub(hx,SS));
result=strcat(re,'=>',re2,' support :',num2str(support(j)),' confidence : ',num2str(confidence));
if length(SS)>1
bcg=[];
for dd=1:length(SS)
bcg=[bcg,SS(dd)];
end
bcg=[bcg,setsub(hx,SS),support(j),confidence];
BCG=[BCG;bcg];
else
cc=setsub(hx,SS);
for cci=1:length(cc)
bgg=[SS,cc(cci),support(j),confidence];
% bg=[re,re2,support(j),confidence];
BGG=[BGG;bgg];
end
end
if (confidence>=thconf)
disp(result) %规则输出
end
end
end
end
end
BG=[BG;BGG];
save('sql1.mat','BG');
save('sql2.mat','BCG');