您的位置:首页 > 其它

关联规则挖掘之算法实现

2014-10-17 18:19 274 查看

一: A Priori的基础实现

算法:Apriori
输入:D -事务数据库;min_sup -最小支持度计数阈值
输出:L - D中的频繁项集
方法:
L1=find_frequent_1-itemsets(D); //找出所有频繁1项集
For(k=2;Lk-1!=null;k++){
Ck=apriori_gen(Lk-1); //产生候选,并剪枝
For each事务t in D{ //扫描D进行候选计数
Ct =subset(Ck,t); //得到t的子集
For each候选c属于Ct
c.count++;
}
Lk={c属于Ck | c.count>=min_sup}
}
Return L=所有的频繁集;
Procedure apriori_gen(Lk-1:frequent(k-1)-itemsets)
For each项集l1属于Lk-1
For each项集l2属于Lk-1
If((l1[1]=l2[1])&&( l1[2]=l2[2])&&……..
&& (l1[k-2]=l2[k-2])&&(l1[k-1]<l2[k-1])) then{
c=l1连接l2 //连接步:产生候选
if has_infrequent_subset(c,Lk-1) then
delete c; //剪枝步:删除非频繁候选
else add c to Ck;}
Return Ck;
Procedure has_infrequent_sub(c:candidate k-itemset; Lk-1:frequent(k-1)-itemsets)
For each(k-1)-subset s of c
If s不属于Lk-1 then
Return true;
Return false;
首先来看一个频繁集的性质。

定理:如果项目集X是频繁集,那么它的非空子集都是频繁集。

根据定理,已知一个k-频繁集的项集X,X的所有k-1阶子集都肯定是频繁集,也就肯定可以找到两个k-1频繁集的项集,它们只有一项不同,且连接后等于X。这证明了通过连接k-1频繁集产生的k-候选集覆盖了k-频繁集。同时,如果k-候选集中的项集Y,包含有某个k-1阶子集不属于k-1频繁集,那么Y就不可能是频繁集,应该从候选集中裁剪掉。Apriori算法就是利用了频繁集的这个性质。

step1: join, 连接k-1频繁集产生的k-候选集覆盖了k-频繁集。

step2: prune, 如果k-候选集中的项集Y,包含有某个k-1阶子集不属于k-1频繁集,那么Y就不可能是频繁集,应该从候选集中裁剪掉。

/*construct C3...................................................*/
vector<Node3> c3;
vector<Node3> l3;

vector<Node2>::iterator ite31=l2.begin();//iter 31,32
for(;ite31!=l2.end();ite31++)
{
vector<Node2>::iterator ite32=l2.begin();
for(;ite32!=l2.end();ite32++)
{
if(ite31->index_j == ite32->index_i) //step1:找到两个k-1频繁集的项集,它们只有一项不同,且连接后等于X
{
vector<Node2>::iterator ite33=l2.begin();
for(;ite33!=l2.end();ite33++)
{
/*step2:如果k-候选集中的项集Y,包含有某个k-1阶子集不属于k-1频繁集,那么Y就不可能是频繁集,应该从候选集中裁剪掉*/
if(ite33->index_i == ite31->index_i && ite33->index_j ==ite32->index_j)
{
Node3 n3(ite31->index_i,ite31->index_j,ite32->index_j,0);
c3.push_back(n3);
}
}
}

}
}


如果不同的k-候选集的最小支持度是相同的,那么并不需要上述中的第二步的prune操作。因为在接下来的扫描D的步骤中是可以裁减掉他的不满足条件的子集的。 如ab+bc=abc, 已知ab和bc已经是k-1介子集,那么如果abc达到了2次的最小支持度,可以成为频繁项集,那么一定会有ac也达到至少2次的支持度。只是如果随着k的增加,最小支持度减少,就必须在k-1介子集中去修剪。
如下是A Priori算法的实现。计算到了L3。

<pre name="code" class="cpp"><pre name="code" class="cpp">/* 这个程序是数据挖掘中的Apriori算法
Apriori算法的描述
Apriori算法的第一步是简单统计所有含一个元素的项集出现的频率,来决定最大的一维项目集.

在第k步,分两个阶段,首先用一函数sc_candidate(候选),通过第(k-1)步中生成的最大项目集Lk-1来生成侯选项目集Ck.  然后搜索数据库计算侯选项目集Ck的支持度. 为了更快速地计算Ck中项目的支持度, 文中使用函数count_support计算支持度.
Apriori算法描述如下
(1)  C1={candidate1-itemsets};
(2)  L1={c∈C1|c.count≥minsupport};
(3)  For(k=2,Lk-1≠Φ,k++) //直到不能再生成最大项目集为止
(4)  Ck=sc_candidate(Lk-1);     //生成含k个元素的侯选项目集
(5)  for all transactions  t∈D        //办理处理
(6)  Ct=count_support(Ck,t);     //包含在事务t中的侯选项目集
(7)  for all candidates c∈Ct
(8)  c.count=c.count+1;
(9)   next
(10)  Lk={c∈Ck|c.count≥minsupport};
(11)  next
(12)  resultset=resultset∪Lk*/

#include <stdio.h>
#include<string.h>
#include <iostream>
#include <vector>
#include <algorithm>
#define D 9 /*D数事务的个数*/
#define MinSupCount 2 /*最小事务支持度数*/
#define ItemN 5
using namespace std;

int hash1(char c)
{
return (int)c-(int)'a';
}
class Node1
{
public:
int index_i;
int count;
Node1()
{
index_i=-1;
count=0;
}
Node1(int i, int c):index_i(i),count(c)
{
}
};
class Node2
{
public:
int index_i;
int index_j;
int count;
Node2()
{
index_i=-1;
index_j=-1;
count = 0;
}
Node2(int i, int j, int c):index_i(i),index_j(j),count(c)
{
}
};
class Node3
{
public:
int index_i;
int index_j;
int index_k;
int count;
Node3()
{
index_i=-1;
index_j=-1;
index_k=-1;
count =0;
}
Node3(int i, int j, int k, int c):index_i(i),index_j(j),index_k(k), count(c)
{
}
};

void printNode3(vector<Node3>& n3)
{
vector<Node3>::iterator ite = n3.begin();
for(;ite!=n3.end();ite++)
{
cout<<(char)(ite->index_i+'a')<<(char)(ite->index_j+'a')<<(char)(ite->index_k+'a')<<":"<<ite->count<<"\t";
}
cout<<endl;
}
void printNode2(vector<Node2>& n2)
{
vector<Node2>::iterator ite = n2.begin();
for(;ite!=n2.end();ite++)
{
cout<<(char)(ite->index_i+'a')<<(char)(ite->index_j+'a')<<":"<<ite->count<<"\t";
}
cout<<endl;
}
void printNode1(vector<Node1>& n1)
{
vector<Node1>::iterator ite = n1.begin();
for(;ite!=n1.end();ite++)
{
cout<<(char)(ite->index_i+'a')<<":"<<ite->count<<"\t";
}
cout<<endl;
}

void main()
{
/*这里的a,b,c,d,e 分别代表着书上数据挖掘那章的I1,I2,I3,I4,I5 */
char a[10][10]={
{'a','b','e'},
{'b','d'},
{'b','c'},
{'a','b','d'},
{'a','c'},
{'b','c'},
{'a','c'},
{'a','b','c','e'},
{'a','b','c'}
};   //total is D

/*c1, hash the first time to b*/
//at first. hash the value
vector<Node1> l1;
int b[10]={0};
int  ItemNumber=0;
for(int i=0;i<D;i++)
{
for(int j=0;a[i][j]!='\0';j++)
{
int item = hash1(a[i][j]);
if(b[item]==0)
{
b[item]++;
ItemNumber++;
}
else
{
b[item]++;
}

}
}
/*L1........................................................*/
for(int i=0;i<ItemNumber;i++)
{
if(b[i]>=MinSupCount)
{
Node1 n1(i,b[i]);
l1.push_back(n1);
}
}
cout<<"print L1................................................"<<endl;
printNode1(l1);

/*construct c2...........................................................*/
vector<Node2> c2;
vector<Node2>l2;
vector<Node1>::iterator ite21=l1.begin(); //ite21,22
for(;ite21!=l1.end();ite21++)
{
vector<Node1>::iterator ite22=l1.begin();
for(;ite22!=l1.end();ite22++)
{
if(ite22->index_i > ite21->index_i)
{
Node2 n2(ite21->index_i,ite22->index_i,0);
c2.push_back(n2);
}
}
}
/*count C2.........................................................................*/
for(int k=0;k<D;k++)
{
for(int i=0;a[k][i]!='\0';i++)
{
int h1 = hash1(a[k][i]);
for(int j=i+1;a[k][j]!='\0';j++)
{
int h2=hash1(a[k][j]);

vector<Node2>::iterator ite=c2.begin();
for(;ite!=c2.end();ite++)
{
if(ite->index_i ==h1 && ite->index_j == h2)
ite->count++;
}
}
}
}
/*prune C2 to L2.......................................................*/
l2.clear();
vector<Node2>::iterator ite2=c2.begin(); //ite2
for(;ite2!=c2.end();ite2++)
{
if(ite2->count>=MinSupCount)
{
l2.push_back(*ite2);
}
}
cout<<"print L2............................................"<<endl;
printNode2(l2);
/*construct C3...................................................*/
vector<Node3> c3;
vector<Node3> l3;

vector<Node2>::iterator ite31=l2.begin();//iter 31,32
for(;ite31!=l2.end();ite31++)
{
vector<Node2>::iterator ite32=l2.begin();
for(;ite32!=l2.end();ite32++)
{

if(ite31->index_j == ite32->index_i)
{
Node3 n3(ite31->index_i,ite31->index_j,ite32->index_j,0);
c3.push_back(n3);
}

}
}
/*countC3.................................................*/
for(int out=0;out<D;out++)
{
for(int i=0;a[out][i]!='\0';i++)
{
int h1 = hash1(a[out][i]);
for(int j=i+1;a[out][j]!='\0';j++)
{
int h2=hash1(a[out][j]);
for(int k=j+1;a[out][k]!='\0';k++)
{
int h3=hash1(a[out][k]);
vector<Node3>::iterator ite=c3.begin();
for(;ite!=c3.end();ite++)
{
if(ite->index_i ==h1 && ite->index_j == h2 && ite->index_k==h3)
ite->count++;
}
}

}
}
}
/*prune C3 to l3....................................*/
l3.clear();
vector<Node3>::iterator ite3=c3.begin(); //ite3
for(;ite3!=c3.end();ite3++)
{
if(ite3->count>=MinSupCount)
{
l3.push_back(*ite3);
}
}
cout<<"print L3..........................."<<endl;
printNode3(l3);
system("pause");
}




下面是代码的结果:
















                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: