Apriori算法的实现

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. 每个项都是候选1项集的集合C1的成员。算法扫描所有的事务,获得每个项,生成C1(见下文代码中的create_C1函数)。然后对每个项进行计数。然后根据最小支持度从C1中删除不满足的项,从而获得频繁1项集L1。
  2. 对L1的自身连接生成的集合执行剪枝策略产生候选2项集的集合C2,然后,扫描所有事务,对C2中每个项进行计数。同样的,根据最小支持度从C2中删除不满足的项,从而获得频繁2项集L2。
  3. 对L2的自身连接生成的集合执行剪枝策略产生候选3项集的集合C3,然后,扫描所有事务,对C3每个项进行计数。同样的,根据最小支持度从C3中删除不满足的项,从而获得频繁3项集L3。
  4. 以此类推,对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");
}
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Apriori算法是常用的数据挖掘算法之一,用于挖掘频繁项集和关联规则。下面是一个简单的Apriori算法实现,供参考。 假我们有一个包含多个事务的数据集,每个事务包含多个项。我们的目标是找到所有出现频率超过某个阈值的项集。 首先,我们需要定义一些变量和函数: - transactions:数据集,每个元素是一个事务,是一个列表。 - threshold:频率阈值,用于筛选频繁项集。 - items:所有项的集合,是一个列表。 - min_support:最小支持度,用于计算频繁项集。 - frequent_sets:频繁项集,是一个字典,key是项集的大小,value是所有该大小的频繁项集的列表。 ``` def apriori(transactions, threshold): items = set() for transaction in transactions: for item in transaction: items.add(item) items = list(items) items.sort() min_support = len(transactions) * threshold frequent_sets = {} # 频繁项集大小为1的情况 frequent_sets[1] = [] for item in items: count = sum([1 for transaction in transactions if item in transaction]) if count >= min_support: frequent_sets[1].append(frozenset([item])) # 频繁项集大小大于1的情况 k = 2 while len(frequent_sets[k-1]) > 0: frequent_sets[k] = [] # 生成候选项集 candidates = set() for i in range(len(frequent_sets[k-1])): for j in range(i+1, len(frequent_sets[k-1])): candidate = frequent_sets[k-1][i] | frequent_sets[k-1][j] if len(candidate) == k and candidate not in candidates: candidates.add(candidate) # 计算支持度 counts = {candidate: 0 for candidate in candidates} for transaction in transactions: for candidate in candidates: if candidate.issubset(transaction): counts[candidate] += 1 # 保留支持度大于等于阈值的项集 frequent_sets[k] = [candidate for candidate in candidates if counts[candidate] >= min_support] k += 1 return frequent_sets ``` 这个实现中,我们首先遍历所有事务,将所有项放入一个集合中。然后按照字典序排序,得到所有项的列表。接着,我们计算出最小支持度min_support,用于筛选频繁项集。接下来,我们初始化频繁项集字典,并计算出频繁项集大小为1的情况。然后,我们依次计算出频繁项集大小为2、3、4...直到没有更多频繁项集为止。 对于每个频繁项集大小k,我们首先生成候选项集。具体来说,我们遍历频繁项集大小为k-1的所有项集,然后取它们的并集,得到所有可能的候选项集。接着,我们遍历所有事务,计算每个候选项集的支持度。最后,我们保留支持度大于等于阈值的项集,即为频繁项集。 需要注意的是,这里我们使用了frozenset来表示项集,因为set不能作为字典的key。此外,我们还使用了一些Python的语法糖,如列表推导式、集合推导式、集合运算等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值