全部版块 我的主页
论坛 数据科学与人工智能 数据分析与数据科学 SAS专版
1182 3
2016-08-21
用数据集的方式进行apriori效率实在太低,使用矩阵的方式速度快很多。不过对于有多个高度相关的项还是会无法处理(产生海量的冗余组合),以下是假设有40个冗余变量的情况(这些变量同时出现),apriori在搜索频繁项的时候就会生成数千亿条冗余组合,这个问题是要在apriori之外搞的。
sss.png
总而言之,用矩阵的方式来实现apriori速度非常快,就是在跑之前要尽量的过滤掉冗余变量。
以下为代码:
ins为输入数据集名称,dim为数字变量的个数,以c1--cn的顺序命名
%macro ap2(ins,dim);
/*1数据集载入矩阵,默认矩阵为m1*/
%im1(&ins,&dim)
/*2执行第一次,并生成一些关键矩阵*/
%im2
/*3执行第二次,生成二项集,并且给出iter_jud来控制循环*/
%im3;
%do iter=3 %to &dim;
%if %eval(&iter-&iter_jud) > 1 %then %goto jumpout;
%im4;
%end;
%jumpout:;
%mend;
%ap2(&ins,&dim)


对应于每个宏:
im1:
%macro im1(ins,vdim);
data m1;
retain c1-c&vdim.;
set &ins;
run;
proc iml ;
use m1;
read all var _num_ into m1;
close m1;
store m1;
quit;
%mend;


im2:
%macro im2;
proc iml;
load m1;
mdim=ncol(m1);
/*支持频数*/
sup=int(nrow(m1)*0.5);
/*支持向量*/
jud=j(1,mdim,sup);
/*全向量 c1*/
vec=j(1,mdim,1);
/*空向量*/
vnull=j(1,mdim,0);
res=vnull;

/*开始计算*/
cal1=m1 & vec;
cal2=cal1[+,];
cal3=cal2 > jud;

/*将f1从cal3从拆解成矩阵*/
do i=1 to mdim;
vtem=vnull;
if cal3 > 0 then do;
vtem=1;
res=res//vtem;
end;
end;
side=res[,+];
res=res[loc(side),];
/*为f1矩阵生成‘侧边栏’*/
side=res[,+];
store  sup  vnull res side;
quit;
%mend;


im3:
%macro im3;
proc iml;
load m1 sup vnull res side;
/*获取项集=1的位置*/
loc=loc(side=1);
/*取出后组成一行数维数即为个数*/
nloc=ncol(loc);       

/*嵌套循环生成候选二项集,先存在候选集里*/
cand=vnull;
do i=1 to nloc-1;
   do j=i+1 to nloc;
/*二项集只要按顺序相加即可生成*/
   vtem=res[i,]+res[j,];
   cand=cand//vtem;
   end;
end;
/*对cand进行频数验证*/
/*cand第一项全0不会通过*/
do i=1 to nrow(cand);
t1=m1 & cand[i,];
t1_sum=t1[+,];
tmax=t1_sum[<>];
if tmax > sup then res=res//cand[i,];
end;
side=res[,+];
iter_jud=side[<>];
call symput('iter_jud',char(iter_jud));
store res side;
quit;
%mend;


im4:
%macro im4;
proc iml;
load m1 sup vnull res side;
iter_c=symget('iter');
iter=num(iter_c);
iter_1=iter-1;
/*取k-1项集,即 iter-1*/
loc=loc(side=iter_1);
nloc=ncol(loc);

/*1 growth*/
/*嵌套循环形成全组合*/
cand=vnull;
cand1=cand;
do i=1 to nloc-1;
   do j=i+1 to nloc;
/*左边部分*/
lf=res[loc,];
loclf=loc(lf);
lflast=loclf[<>];
lftem=lf;
lftem[lflast]=0;
/*右边部分*/
rt=res[loc[j],];
locrt=loc(rt);
rtlast=locrt[<>];
rttem=rt;
rttem[rtlast]=0;
/*判断部分*/
if lftem = rttem then do;
mer=lf+rt;
mer=mer > 0;
cand=cand//mer;
end;
end;
end;


/*这里应该生成完整的cand,必须要把cand首项移除,否则空值无法继续*/
/*计算侧边栏*/
side_tem=cand[,+];
/*去除第一行空值*/
cand=cand[loc(side_tem),];
/*计算真实的侧边栏*/
side_tem=cand[,+];
/*计算侧边栏的项*/
nrow=nrow(side_tem);


/*2 剪枝*/
/*获取iter-1项集*/
/*获取iter-1项集下标,利用侧边栏*/
loccm=loc(side=iter_1);
cm=res[loccm,];
/*对cand中每一项循环*/
do i=1 to nrow(cand);
check=cand[i,];
ck=0;
/*获取检查向量的1下标*/
loc_tem=loc(check);
/*每项循环k次进行检查*/
do j=1 to iter;
tem=check;
tem[loc_tem[j]]=0;
tem_a=cm & tem;
tem_b=tem_a[,+];
tem_c=tem_b[<>];
/*如果检查数正确那么计数加1*/
if tem_c = iter_1 then ck=ck+1;
else goto mm;
/*如果k项检查都通过,那么把这项附加到cand1中*/
if ck=iter then cand1=cand1//check;
end;
mm:;
end;

/*3再次扫描进行频繁项检查*/
do i=1 to nrow(cand1);
t1=m1 & cand1[i,];
t1_sum=t1[+,];
tmax=t1_sum[<>];
if tmax > sup then res=res//cand1[i,];
end;
side=res[,+];
iter_jud=side[<>];
call symput('iter_jud',char(iter_jud));
store res side;
quit;
%mend;
ap2.txt
大小:(3.74 KB)

只需: 1 个论坛币  马上下载





二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

全部回复
2016-8-21 15:33:56
强烈建议经管之家增加代码编辑器的功能
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

2016-8-21 15:55:01
siliconMagic 发表于 2016-8-21 15:33
强烈建议经管之家增加代码编辑器的功能
碰到很多次符号被吞掉的情况,所以我附了一个txt
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

2016-8-21 18:39:56
频繁项检查有个错误,比如二项集,扫描频繁项的时候应该是 x1=1 and x2=1 才能被计数,原来的写法是错的,应该加入*号夹的那几行
do i=1 to nrow(cand);
t1=m1 & cand[i,];
**************************
/*选取侧边栏对应的记录*/
side_tem=t1[,+];
loc_tem=loc(side_tem=2);
t1_tem=t1[loc_tem,];
*************************
t1_sum=t1_tem[+,];
tmax=t1_sum[<>];
if tmax > sup then res=res//cand[i,];
end;
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

相关推荐
栏目导航
热门文章
推荐文章

分享

扫码加好友,拉您进群