Apriori使用一种称作逐层搜索的迭代方法,k项集用于探索(k+1)项集。 首先,通过扫描数据库,累计每个项的计数,并收集满足最小支持度的项,找出频繁1项集的集合。该集合记作L1。然后,L1用于找频繁2项集的集合L2,L2用于找L3,如此下去直到不能再找到频繁k项集。找每个Lk需要一次数据库全扫描。
Apriori定律1 :如果某商品组合小于最小支持度,则就将它舍去,它的超集必然不是频繁项集。
Apriori定律2 :如果一个集合是频繁项集,即这个商品组合支持度大于最小支持度,则它的所有子集都是频繁
数据库有5个事务。设min_sup=60%,min_conf=80%
TID |
购买的商品 |
T100 |
{M,O,N,K,E,Y} |
T200 |
{D,O,N,K,E,Y} |
T300 |
{M,A,K,E} |
T400 |
{M,U,C,K,Y} |
T500 |
{C,O,O,K,I,E} |
在程序中,使用Apriori算法,找出频繁项集
步骤:
- 每个项都是候选1项集的集合C1的成员。算法扫描所有的事务,获得每个项,生成C1(见下文代码中的create_C1函数)。然后对每个项进行计数。然后根据最小支持度从C1中删除不满足的项,从而获得频繁1项集L1。
- 对L1的自身连接生成的集合执行剪枝策略产生候选2项集的集合C2,然后,扫描所有事务,对C2中每个项进行计数。同样的,根据最小支持度从C2中删除不满足的项,从而获得频繁2项集L2。
- 对L2的自身连接生成的集合执行剪枝策略产生候选3项集的集合C3,然后,扫描所有事务,对C3每个项进行计数。同样的,根据最小支持度从C3中删除不满足的项,从而获得频繁3项集L3。
- 以此类推,对Lk-1的自身连接生成的集合执行剪枝策略产生候选k项集Ck,然后,扫描所有事务,对Ck中的每个项进行计数。然后根据最小支持度从Ck中删除不满足的项,从而获得频繁k项集。
vc代码:
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
#define D 5 /*D数事务的个数*/
#define MinSupCount 3 /*最小事务支持度数*/
void main()
{
char a[5][6] = {
{ 'M','O','N','K','E','Y' },
{ 'D','O','N','K','E','Y' },
{ 'M','A','K','E' },
{ 'M','U','C','K','Y'},
{ 'C','O','O','K','I','E' }
};
char b[20], d[100], t, b2[100][10], b21[100][10];//b用来保存数据库中的元素
int i, j, k, x = 0, flag = 1, c[20] = { 0 }, x1 = 0, i1 = 0, j1, counter = 0, c1[100] = { 0 }, flag1 = 1, j2, u = 0, c2[100] = { 0 }, n[20], v = 1;
int count[100], temp;
for (i = 0; i<D; i++)
{
for (j = 0; a[i][j] != '\0'; j++)
{
/*这个循环是用来判断之前保存的是否和a[i][j]一样,不一样就保存,一样就不保存*/
for (k = 0; k<x; k++)
{
if (b[k] != a[i][j]);//b[k]是已存储的项,已存储的项不等于现在存储的,意味着有新元素。
else
{
flag = 0; break;
}
}
/*这个if是用来判断是否相等*/
if (flag == 1)
{
b[x] = a[i][j];
x++;
}
else flag = 1;/*这个不保存,那就跳到下一个数*/
}
}
//数组b用于存放元素,即x就是元素种类的个数
/*计算筛选出的元素的支持度计数*/
for (i = 0; i<D; i++)
{
for (j = 0; a[i][j] != '\0'; j++)
{
for (k = 0; k<x; k++)/*这个x是上面b数组中元素个数,用b数组和a[i][j]数组中的每一行和每一列进行比较,用来记录b数组每一个元素的支持度计数*/
{
if (a[i][j] == b[k])
{
c[k]++; break;
}
}
}
}
//数组c用于存放每个元素的支持度计数
for (k = 0; k<x; k++)
{
if (c[k] >= MinSupCount)
{
d[x1] = b[k];
count[x1] = c[k];
x1++;//L1中元素的个数
}
}
//数组D即为L1
/*对选出的项集中的元素进行排序*/
for (i = 0; i<x1 - 1; i++)
{
for (j = 0; j<x1 - i - 1; j++)
{
if (d[j]>d[j + 1])
{
t = d[j]; d[j] = d[j + 1]; d[j + 1] = t;
temp = count[j]; count[j] = count[j + 1]; count[j + 1] = temp;
}
}
}
/*打印出L1*/
printf("L1 elements are:\n");
for (i = 0; i<x1; i++)
{
printf("{%c} = %d ", d[i], count[i]);
}
printf("\n");
/*计算事务的项的个数,并且保存到n[]数组中*/
for (i = 0; i<D; i++)
{
for (j = 0; a[i][j] != '\0'; j++);
n[i] = j;
}
//数组n表示各事务中的元素个数
/*对a[][]数组的每一行进行排序*///对本例没影响,因为已经排好了序
for (i = 0; i<D; i++)
{
for (j = 0; j<n[i] - 1; j++)
{
for (k = 0; k<n[i] - j - 1; k++)
{
if (a[i][k]>a[i][k + 1])
{
t = a[i][k];
a[i][k] = a[i][k + 1];
a[i][k + 1] = t;
}
}
}
}
/*把L1中的每一个元素都放在b2[i][0]中*/
j1 = x1;//j1初始设置为L1中元素的个数。
for (i = 0; i<j1; i++)
{
b2[i][0] = d[i];
}
/*把L1中的元素进行组合,K=2开始,表示x1个元素选K个元素的组合(x1是频繁一项集个数)*/
for (k = 2; b2[0][0] != '\0'; k++)
{ /*u是用来计数候选集中的组合总数的*/
u = 0; v = 1;/*v 是用来在进行输出各种组合的标识数 v=1 说明正在进行输出*/
for (i = 0; i<100; i++)
{
c2[i] = 0;//频繁项集Lk中元素的支持度计数
}
for (i = 0; i<j1; i++)//j1是Lk-1中的集合个数,初始为L1中的集合个数x1
{
for (i1 = i + 1; i1<j1; i1++)
{
for (j = 0; j<k - 2; j++)
{
//k-2之前只要有不同的,说明不能链接,标记flag1为0
if (b2[i][j] != b2[i1][j])
{
flag1 = 0; break;
}
}
/*进行组合的部分*/
if (flag1 == 1 && b2[i][k - 2] != b2[i1][k - 2])//可以链接并且最后一个元素不相等
{
for (j2 = 0; j2<k - 1; j2++)
{
b21[u][j2] = b2[i][j2]; //k-1个元素保持不变
}
b21[u][k - 1] = b2[i1][k - 2]; //第k个元素加上不同的那个
u++;
}
flag1 = 1;
}
}
//b21为候选集
counter = 0;//候选k项集中的元素在某个事务中出现的次数
for (i = 0; i<D; i++)/*找候选项集Ck中满足支持度计数的*///扫描D
{
for (i1 = 0; i1<u; i1++)/*U=Ck中所有组合总数*/
{
for (j1 = 0; j1<k; j1++)/*K 代表一个组合中的元素个数*/
{
for (j = 0; a[i][j] != '\0'; j++)/*逐个比较每一行的元素*/
{
if (b21[i1][j1] == a[i][j])
{
counter++;
break;
}
}
}
if (counter == k)
c2[i1]++;
/*把候选集是事务的子集的计数记录在c2数组中(只要满足有k个元素在某个事务中,则计数加1)*/
counter = 0;
}
}
j1 = 0; temp = 0;/*这里的temp 是用来分行*/
/*对u种情况进行选择,选出支持度计数大于2的*/
//j1对Lk中的集合个数计数,每次在输出前重置。
for (i = 0; i<u; i++)
{
if (c2[i] >= MinSupCount)
{
if (v == 1)
{
printf("L%d elements are:\n", k);
v = 0;
}
printf("{");
for (j = 0; j<k; j++)/*输出每种组合k 个元素*/
{
b2[j1][j] = b21[i][j];
printf("%c,", b2[j1][j]);
}
j1++; //Lk计数加1
printf("\b}");
printf(" = %d ", c2[i]);
if (0 == (temp + 1) % 3) //printf("\n");
temp++;
}
}
b2[j1][0] = '\0';//j1是Lk中的集合个数
if (b2[0][0] != '\0')
printf("\b \n");
}
system("pause");
}