Apriori算法是一个容易理解,逻辑简单,代码容易编写的一个大数据频繁项集查找的算法。
设最小支持度计数为3 即个数要大于等于3的才是频繁项
如图1--原始数据库 计数得到图2--每个东西的个数 则得到图3的频繁一项
图1 图2 图3
由频繁一项集两两配对得到候选项集合{A,B},{A,E},{B,E}
扫面原始数据库,即图1
{A,B}2个,{A,E}3个,{B,E}1个,所以得到频繁二项集{A,E}。由于此时二项集只剩下一个了,所以无法产生三项集,故程序结束。
看如下图所示程序流程图:
图5(图片来源于网络,仅供学习参考)
C++代码:完整说明以及大数据测试数据可以从这里下载http://download.csdn.net/download/my_acm/8042909
本程序为了简单编程使用直接把原始数据读入内存中,所以不能处理非常大的数据,而正真的apriori算法处理超大规模数据时会一遍一遍的从数据库中读取数据。这也是为什么apriori算法效率不高的原因之一。
/* function: apriori算法查找频繁集 authour: date: Code::Blocks 12.11下运行通过 */ #include<vector> #include<iostream> #include<cstring> #include<stdio.h> #include<algorithm> #include<math.h> #include<map> using namespace std; #define maxn 100000 #define maxItem 90 #define suport 0.01 //最小支持度 struct Item{ vector <int> num; }; typedef vector <int> i_list; class Apriori{ public: int suport_num; //最小支持度计数 int num_max; //单行最大数量 int num_sol; //交易条数 int num_fre; //频繁项种类的数量 Item item[maxn]; //初始交易信息 vector <i_list> fre_item[maxn]; //保存所有频繁项信息,fre_item[i]表示频繁i项信息 map <int,int> list_item; //标记某一个项目序号的总数 public: void init(){ num_fre=0; num_max=0; suport_num=0; num_sol=0; } void input(){ //输入,初始化交易信息 char str[3000]; int t=0; while(gets(str)){ //按行逐个读入数据 char *f; f=strtok(str," "); while(f){ int x; x=atoi(f); list_item[x]++; //商品计数 item[t].num.push_back(x); f=strtok(NULL," "); } if(item[t].num.size()>num_max) num_max=item[t].num.size(); t++; } num_sol=t; for(int i=0;i<num_sol;i++){ sort(item[i].num.begin(),item[i].num.end()); //交易项目序号从小到大排列 } suport_num=ceil(suport*num_sol); //最小支持度计数 cout<<"数据总行数: "<<num_sol<<" 最小支持度"<<suport<<" 最小支持度计数: "<<suport_num<<endl; // for(int i=0;i<num_sol;i++){ // int len=item[i].num.size(); // for(int j=0;j<len;j++){ // printf("%d ",item[i].num[j]); // } // printf("\n"); // } } void output(){ //输出频繁项集 if(!fre_item[1].size()){ printf("no frequent item!\n"); return ; } for(int k=1;k<=num_fre;k++){ printf("%d frequent item is:\n",k); for(int i=0;i<fre_item[k].size();i++){ for(int j=0;j<fre_item[k][i].size();j++){ printf("%d ",fre_item[k][i][j]); } printf("\n"); } printf("\n"); } } void LCS(i_list &tmp,i_list &t1,i_list &t2){//匹配最长公共子序列 int len=t1.size(); int sucess=1; for(int i=0;i<len-1;i++){ if(t1[i]!=t2[i]){ sucess=0; break; } } if(t1[len-1]==t2[len-1]) sucess=0; if(sucess){ tmp=t1; tmp.push_back(t2[len-1]); } } int judge(i_list tmp){ //判断tmp是否是频繁项 int len=tmp.size(); int sum=0; int sucess=1; for(int i=0;i<num_sol;i++){ //遍历所有原始数据 sucess=1; if(item[i].num.size()<len) continue; for(int k=0;k<len;k++){ int j; int tlen=item[i].num.size(); for(j=0;j<tlen;j++){ if(tmp[k]==item[i].num[j]) break; } if(j>=tlen){ sucess=0; break; } } if(sucess) sum++; } if(sum>=suport_num) //大于等于最小支持度则是频繁项 return 1; return 0; //不是频繁项 } void find_fre_item(){ //找出所有频繁项 for(map <int,int>::iterator it=list_item.begin();it!=list_item.end();it++){ //找出所有的频繁一项 if(it->second>=suport_num){ i_list tmp; tmp.push_back(it->first); fre_item[1].push_back(tmp); } } list_item.clear(); //释放lisg_item if(0==fre_item[1].size()) return ; if(1==fre_item[1].size()){ num_fre=1; return ; } int len=num_max; for(int k=2;k<=len;k++){ //找出所有二项以后的频繁项集 //枚举k-1项的所有单项的数据,进行LCS匹配,得到k频繁项 if(fre_item[k-1].size()>=2) for(int i=0;i<fre_item[k-1].size();i++){ for(int j=i+1;j<fre_item[k-1].size();j++){ i_list tmp; tmp.clear(); LCS(tmp,fre_item[k-1][i],fre_item[k-1][j]); if(!tmp.size()) continue; if(judge(tmp)){ fre_item[k].push_back(tmp); num_fre=k; } } } } } void calculate_fre_item(){ //频繁项计算 init(); input(); find_fre_item(); output(); } }sol; int main(){ freopen("retail.dat","r",stdin); freopen("result.txt","w",stdout); sol.calculate_fre_item(); return 0; }
原文地址:http://blog.csdn.net/my_acm/article/details/41850831