1.首先处理输入数据文件中数据的读入,数据存放在BUC.csv文件中,
每一行为一组维度组合序列,表示该序列出现一次。读取该文件,将数据保存在列表record中,保存形式如下:
record = [[‘a1’,‘b1’,‘c1’],[‘a2’,‘b1’,‘c2’]...]
返回record记录的同时返回不同维度的类别,如[‘a’,‘b’,‘c’]
本部分代码如下:
#读取文件,并将数据存储到record中def readFile(filename):record = []fr = open(filename,'r')for line in fr:line = line.replace('\n','').split(',')record.append(line)#print([x[0] for x in record[0]])Dims = ([x[0] for x in record[0]])return record,Dims
2.根据第一步取得的总记录record和设置的最小支持度阈值min_sup,判断总记录条数是否大于min_sup,若总记录条数小于min_sup,则不可能有频繁项出现。代码如下:
#首先检查所有记录总数是否大于min_Supdef Examine(record,min_sup):num = 0for rec in record:num += 1if num >= min_sup:return Trueelse:return False
3.根据第一步取得的总记录record和设置的最小支持度阈值min_sup,求出每个维度的每一个取值出现的次数,并返回那些出现次数满足min_sup的值,即返回单个项的频繁项,代码如下:
#计算每个维度的取值个数(如A类有a1、a2、a3、a4,计数为4)DimCountAll 如[4、2、2、1]#并返回所有维度的取值集合 DimAll 如[[a1、a2、a3、a4]、[b1、b2]、[c1、c2]、[d1]]#计算每一个维度的每一个取值出现的次数#只返回那些出现次数满足min_Sup的值,def Count_for_every_value(record,min_sup):dic = dict()for dim in range(0,len(record[0])):for value in range(len(record)):if record[value][dim] not in dic:dic[record[value][dim]] = 1else:dic[record[value][dim]] += 1result = {x: dic[x] for x in dic if dic[x] >= min_sup}return result
4.正式进行BUC计算,首先根据步骤二中筛选出的频繁项K1i(存储在dim_list中),针对每一个频繁项,都遍历一遍所有的记录,对所有包含当前频繁项的序列的子序列C2i(存储在item_count中)的出现次数进行计数,并筛选出出现次数大于min_sup的C2i,记作K2i(存储在清空后的dim_list中,清空dim_list是为了防止输出时重复输出之前输出过的频繁项)。此时,完成了第一次迭代,将当前之存放了K2i的dim_list和当前迭代次数d作为参数进行第二次迭代。以此类推,直至完成所有迭代过程。
关于细节方面,针对单项的频繁项是很好处理的,针对包含多项的频繁项,我首先用中间变量将
[‘a1 b1’]这种包含两项(或多项)的频繁项转化为a1b1,将每一条记录转化成形如a1b1c1d1,通过判断a1b1在不在a1b1c1d1里面,来组合成如C3i这种新的待选子序列并对其计数;为了防止针对每次迭代都从每条记录的头部开始,我声明了一个表示当前频繁项所包含项数的偏移量offset,从而大大减少了工作量。
代码如下:
5.运行程序,其中BUC.csv文件内容如下:
#record为所有的记录,count_for_every_value为所有频繁序列的计数字典,#Dims为所有类别的列表,d为当前递归到了第几个类def BUC(record,count_for_every_value,Dims,d,min_sup):if d > len(Dims):return 0dim_list = list(count_for_every_value)#遍历当前筛选出的每一个频繁项item_count = {}for dim_value in dim_list:#sentence针对每一个如['a1','b1']这样的多项频繁项,将其转化为 a1b1if len(dim_value.split(' ')) >=1:sentence = ""# offset记录当前的组合序列有几项,# 如有2项,则在所有记录中进行进一步查找频繁项的过程中从每个记录的第三项找起offset = 0for dim in dim_value.split():offset +=1sentence += dim#针对每一个频繁项,遍历每一条记录for rec in record:#变量temp将rec从['a1','b1','c1','d1']的形式变为a1b1c1d1temp = ""for dim in rec:temp += dim#若当前记录存在该频繁项,则进行如下操作if sentence in temp:#遍历每一条记录的 从频繁项往后的 每一项for item in rec[offset+1:]:#如果当前项和频繁项不是同一项(这一个判断可能多余了)#对当前项和频繁项的组合进行计数,并存储到item_count中,# 如['a1 b1 c1' : 3 , 'a1 b2' : 5]if item[0] not in dim_value:item = ' '.join([dim_value]+[item])if item not in item_count:item_count[item] = 1else:item_count[item] += 1#dim_list用于存储当前次递归所得到的所有频繁项dim_list = []for item in item_count:if item_count[item] >= min_sup:dim_list.append(item)#当dim_list不为空时,输出dim_listif len(dim_list) > 0:print(dim_list)#进行下一次递归操作,不要忘记d+1,用于递归结束的判断d += 1BUC(record,dim_list,Dims,d,min_sup)return 0
5.运行程序,其中BUC.csv文件内容如下:
a1,b1,c1,d1a1,b2,c2,d2a1,b3,c2,d1a1,b4,c1,d2a2,b1,c1,d1a2,b2,c2,d2a2,b3,c2,d1a2,b4,c1,d2a3,b1,c1,d1a3,b2,c2,d2a3,b3,c2,d1a3,b4,c1,d2a4,b1,c1,d1a4,b2,c2,d2a4,b3,c2,d1a4,b4,c1,d2
输出如下:
['a1', 'a2', 'a3', 'a4', 'b1', 'b2', 'b3', 'b4', 'c1', 'c2', 'd1', 'd2']['b1 c1', 'b1 d1', 'b2 c2', 'b2 d2', 'b3 c2', 'b3 d1', 'b4 c1', 'b4 d2', 'c1 d1', 'c1 d2', 'c2 d2', 'c2 d1', 'd1 c1', 'd1 c2', 'd2 c2', 'd2 c1']['b1 c1 d1', 'b2 c2 d2', 'b3 c2 d1', 'b4 c1 d2']
完整代码如下:
#读取文件,并将数据存储到record中def readFile(filename):record = []fr = open(filename,'r')for line in fr:line = line.replace('\n','').split(',')record.append(line)#print([x[0] for x in record[0]])Dims = ([x[0] for x in record[0]])return record,Dims#首先检查所有记录总数是否大于min_Supdef Examine(record,min_sup):num = 0for rec in record:num += 1if num >= min_sup:return Trueelse:return False#计算每个维度的取值个数(如A类有a1、a2、a3、a4,计数为4)DimCountAll 如[4、2、2、1]#并返回所有维度的取值集合 DimAll 如[[a1、a2、a3、a4]、[b1、b2]、[c1、c2]、[d1]]#但是这里并没有用到这一函数。def CountAllDim(record):DimCountAll = []DimAll = []for i in range(0,len(record[0])):#temp用于暂存针对当前这一维度的不同取值temp = []for j in range(0,len(record)):if record[j][i] not in temp:temp.append(record[j][i])DimAll.append(temp)DimCountAll.append(len(temp))return DimCountAll,DimAll#计算每一个维度的每一个取值出现的次数#只返回那些出现次数满足min_Sup的值,def Count_for_every_value(record,min_sup):dic = dict()for dim in range(0,len(record[0])):for value in range(len(record)):if record[value][dim] not in dic:dic[record[value][dim]] = 1else:dic[record[value][dim]] += 1result = {x: dic[x] for x in dic if dic[x] >= min_sup}return result#record为所有的记录,count_for_every_value为所有频繁序列的计数字典,# Dims为所有类别的列表,d为当前递归到了第几个类def BUC(record,count_for_every_value,Dims,d,min_sup):if d > len(Dims):return 0dim_list = list(count_for_every_value)#遍历当前筛选出的每一个频繁项item_count = {}for dim_value in dim_list:#sentence针对每一个如['a1','b1']这样的多项频繁项,将其转化为 a1b1if len(dim_value.split(' ')) >=1:sentence = ""# offset记录当前的组合序列有几项,# 如有2项,则在所有记录中进行进一步查找频繁项的过程中从每个记录的第三项找起offset = 0for dim in dim_value.split():offset +=1sentence += dim#针对每一个频繁项,遍历每一条记录for rec in record:#变量temp将rec从['a1','b1','c1','d1']的形式变为a1b1c1d1temp = ""for dim in rec:temp += dim#若当前记录存在该频繁项,则进行如下操作if sentence in temp:#遍历每一条记录的 从频繁项往后的 每一项for item in rec[offset+1:]:#如果当前项和频繁项不是同一项(这一个判断可能多余了)#对当前项和频繁项的组合进行计数,并存储到item_count中,# 如['a1 b1 c1' : 3 , 'a1 b2' : 5]if item[0] not in dim_value:item = ' '.join([dim_value]+[item])if item not in item_count:item_count[item] = 1else:item_count[item] += 1#dim_list用于存储当前次递归所得到的所有频繁项dim_list = []for item in item_count:if item_count[item] >= min_sup:dim_list.append(item)#当dim_list不为空时,输出dim_listif len(dim_list) > 0:print(dim_list)#进行下一次递归操作,不要忘记d+1,用于递归结束的判断d += 1BUC(record,dim_list,Dims,d,min_sup)return 0if __name__ == '__main__':result = []filename = './BUC.csv'record,Dims = readFile(filename)min_sup = 3if Examine(record, min_sup):count_for_every_value = Count_for_every_value(record,min_sup)#list的作用是将字典的key值全部取出,并生成list#即先将单项的频繁序列输出print(list(count_for_every_value))BUC(record,count_for_every_value,Dims,2,min_sup)#if Examine(record,3):#DimCountAll,DimAll=CountAllDim(record)
这次实现的算法还有很大的优化空间,比如先从分区最多的维度进行BUC的剪枝操作,本例中的**CountAllDim(record)**函数也是为这一目的而编写,但因为时间关系并没有实现它,可以留待以后完成这一优化。
如果觉得《数据挖掘冰山立方体的构建:BUC算法的实现》对你有帮助,请点赞、收藏,并留下你的观点哦!