【算法大致描述】
Aprior算法主要有两个操作,扫描数据库+统计。计算每一阶频繁项集都要扫描一次数据库并且统计出满足支持度的n阶项集。
【算法主要步骤】
一、频繁一项集
算法开始第一步,通过扫描数据库,统计出每条记录中出现的每一个单独项并计数,数据库扫描完成,统计结束,根据支持度,选出满足条件的频繁一项集 L1。
二、连接
用 Lk-1自连接得到Ck。
方法,如果Lk-1中的两个元素的前K-2项都相同,只有最后一项不同,则自连接得到Ck中的一个元素。例如L3{(12,13,14),(12,13,15) }则可自连接得到C4{(12 13 14 15)}
三、修剪
对于自连接得到的Ck,其中有些元素是可以不用扫描数据库就可以确定它肯定不是频繁项集的。一个k-项集,如果它的一个k-1项集(它的子集 )不是频繁的,那它本身也不可能是频繁的。
例如L3{(12 ,13,14),(12,13,15)}自连接得到C4{(12,13,14,15)} 但是(13,14,15)不在L3中,所以可以肯定(12,13,14,15)不是频繁四项集,不用再去扫描数据库。
通过修剪,可以很快的减少Ck中的元素,减少数据库的扫描次数,大大加快效率。
四、扫描数据库得到频繁k项集Lk
将已经修剪过的Ck中的每一个元素拿到数据库中去找,统计出现次数,根据支持度得到结果。
C++源码
#include #include<string> #include #include using namespace std; vector <string> result; map<string,int>r1; float suport; vector<string> file; void Getfile(){ ifstream ifile("D://retail.dat"); if(!ifile){ cout<<"open file error"<<endl; } else{ string temp; while(getline(ifile,temp)){ file.push_back(temp); } } ifile.close(); } bool IsrealCk(vector<string>& Lk ,vector<string> &str){//判断str的子集是否在Lk-1中 string temp; int i; for( i=0;i){ temp.clear(); for(int j=0;j//Cn 1 if(j!=i){ temp+=str[j]; temp.push_back(','); } }//生成一个子集 temp.erase(temp.size()-1); int k; for( k=0;k// if(Lk[k]==temp) break; } if(k>=Lk.size()){//不在Lk break; } } if(i>=str.size()) return 1; else return 0; } vector<string> minCK(vector<string>& Lk,vector<string>& Ck){//剪枝 (12,45,32) vector<string> minck; vector<string> str; for(int i=0;i){ string s; str.clear(); for(int j=0;j){ while(Ck[i][j]!=','&&j<Ck[i].size()){ s.push_back(Ck[i][j]); j++; } str.push_back(s); s.clear(); } if(IsrealCk(Lk,str)){ minck.push_back(Ck[i]); } } return minck; } vector<string> GetL1_C2(){ vector <string> L1; vector<int> count; vector<string> l1; vector<string> C2; string temp; int line=0; string lk; for(int f=0;f){ temp=file[f]; line++; int i; for( i=0;i){ while(temp[i]!=' '&&temp[i]!='\n'&&i!=temp.size()){ lk+=temp[i]; i++; } if(r1.find(lk)!=r1.end()) r1[lk]++; else r1[lk]=1; lk.clear();// } } temp.clear(); map<string,int>::iterator it; for(it=r1.begin();it!=r1.end();it++){//待删除 if(it->second>=ceil(suport*line)){ cout<first<<" ("<second<<")"<<endl; result.push_back(it->first); } } for(int i=0;i){ for(int j=i+1;j){ string c2=result[i]+","+result[j]; C2.push_back(c2); } } return C2; } vector<string> CK(vector<string>& L){ vector<string> Ck;//k+1候选像集 vector<string> minck; for(int i=0;i){ for(int j=i+1;j){ if(i!=j){ string temp1,temp2; int m1,m2; for(m1=L[i].size()-1;m1>0;m1--){ if(L[i][m1]==',') break; } temp1=L[i].substr(0,m1+1); for(m2=L[j].size()-1;m2>0;m2--){ if(L[j][m2]==',') break; } temp2=L[j].substr(0,m2+1); if(temp1==temp2){//可以连接 string lk=temp1; for(int x=m1+1;x) { lk.push_back(L[i][x]); } lk.insert(lk.end(),','); for(int x=m2+1;x) { lk.push_back(L[j][x]); } Ck.push_back(lk);//加入候选项 } } } } // minck=minCK(L,Ck); return minck=minCK(L,Ck); } bool Isin(string& temp,string& str){ int j; string s; for( j=0;j//遍历temp while(temp[j]!=' '&&j<temp.size()){ s.push_back(temp[j]); j++; } if(s==str) break; s.clear(); } if(j>=temp.size()) return 0; else return 1; } vector<string> GetLk(vector<string>& Ck){ map<string,int> Lk; string temp; int flag=0; int line=0; for(int f=0;f){ temp=file[f]; line++;int t=0; vector<string> str; for(int i=0;i){ string s;//记录单个元素 12,32 s=12 str.clear(); for( int j=0;j//遍历 12,34 while(Ck[i][j]!=','&&j<Ck[i].size()){ s.push_back(Ck[i][j]); j++; } str.push_back(s); s.clear(); } int p; for( p=0;p){ if(!Isin(temp,str[p])) break; } if(p>=str.size()){//在temp中出现 if(Lk.find(Ck[i])!=Lk.end()) Lk[Ck[i]]++; else Lk[Ck[i]]=1; } } } /*********/ temp.clear(); vector<string> ck; map<string,int>::iterator it; for( it=Lk.begin();it!=Lk.end();it++){//待删除 if(it->second>=ceil(suport*line)){ ck.push_back(it->first); } } return ck; } void Apri(vector<string>& Ck){ if(Ck.size()<1){ return ; } else{ vector<string> temp=GetLk(Ck); if(temp.size()<1) return; else{ for(int i=0;i){ result.push_back(temp[i]);//记录Lk } vector<string>nextck= CK(temp); Apri(nextck); } } } int main(){ cout<<"请输入最小支持度"<<endl; cin>>suport; Getfile(); int c=0; vector<string> C2=GetL1_C2(); Apri(C2); cout<<"频繁项集如下:"<<endl; for(int i=0;i){ cout<endl; c++; } cout<<" count "<endl; return 0; }
测试文件(有八万多条记录,测试代码建议跑0.1支持度)
https://pan.baidu.com/s/1Lp7LJOXksIRh3KBra2iVIw