当前位置:   article > 正文

Educoder-Apriori基于hash的支持度计算_apriori使用hash树计算支持度

apriori使用hash树计算支持度

任务描述

本关任务:编写一个能实现基于 hash 的支持度计算的小程序。

相关知识

为了完成本关任务,你需要掌握:1.基于 hash 的支持度计算,2.基于 hash 的支持度计算代码实现。

基于hash的支持度计算

基于遍历的支持度计算非常耗时间,而基于 hash 的支持度计算可以将所有候选项集以 hash 结构中,每条事务只需要匹配其对应桶里的候选项集,从而节省时间开销。

假设有15个候选3-项集: {1 4 5}, {1 2 4}, {4 5 7}, {1 2 5}, {4 5 8}, {1 5 9}, {1 3 6}, {2 3 4}, {5 6 7}, {3 4 5}, {3 5 6}, {3 5 7}, {6 8 9}, {3 6 7}, {3 6 8}

可构建如下 hash 树: 树的每个内部结点都使用hash函数h(p)=p mod 3来确定应当沿着当前结点的哪个分支向下。例如,项 1,4 和 7 应当散列到相同的分支(即最左分支),因为除以 3 之后它们都具有相同的余数。所有的候选项集都存放在hash树的叶结点中。下图图中显示的 hash 树包含 15个候选 3-项集,分布在 9 个叶结点中。

构建过程如下:

任务描述

本关任务:编写一个能实现基于 hash 的支持度计算的小程序。

相关知识

为了完成本关任务,你需要掌握:1.基于 hash 的支持度计算,2.基于 hash 的支持度计算代码实现。

基于hash的支持度计算

基于遍历的支持度计算非常耗时间,而基于 hash 的支持度计算可以将所有候选项集以 hash 结构中,每条事务只需要匹配其对应桶里的候选项集,从而节省时间开销。

假设有15个候选3-项集: {1 4 5}, {1 2 4}, {4 5 7}, {1 2 5}, {4 5 8}, {1 5 9}, {1 3 6}, {2 3 4}, {5 6 7}, {3 4 5}, {3 5 6}, {3 5 7}, {6 8 9}, {3 6 7}, {3 6 8}

可构建如下 hash 树: 树的每个内部结点都使用hash函数h(p)=p mod 3来确定应当沿着当前结点的哪个分支向下。例如,项 1,4 和 7 应当散列到相同的分支(即最左分支),因为除以 3 之后它们都具有相同的余数。所有的候选项集都存放在hash树的叶结点中。下图图中显示的 hash 树包含 15个候选 3-项集,分布在 9 个叶结点中。

构建过程如下:

任务描述

本关任务:编写一个能实现基于 hash 的支持度计算的小程序。

相关知识

为了完成本关任务,你需要掌握:1.基于 hash 的支持度计算,2.基于 hash 的支持度计算代码实现。

基于hash的支持度计算

基于遍历的支持度计算非常耗时间,而基于 hash 的支持度计算可以将所有候选项集以 hash 结构中,每条事务只需要匹配其对应桶里的候选项集,从而节省时间开销。

假设有15个候选3-项集: {1 4 5}, {1 2 4}, {4 5 7}, {1 2 5}, {4 5 8}, {1 5 9}, {1 3 6}, {2 3 4}, {5 6 7}, {3 4 5}, {3 5 6}, {3 5 7}, {6 8 9}, {3 6 7}, {3 6 8}

可构建如下 hash 树: 树的每个内部结点都使用hash函数h(p)=p mod 3来确定应当沿着当前结点的哪个分支向下。例如,项 1,4 和 7 应当散列到相同的分支(即最左分支),因为除以 3 之后它们都具有相同的余数。所有的候选项集都存放在hash树的叶结点中。下图图中显示的 hash 树包含 15个候选 3-项集,分布在 9 个叶结点中。

构建过程如下:

给定一个事务 t , 跟哪些候选 3 项集匹配?例如下图中的例子: 匹配过程如下: 考虑一个事务 t={1,2,3,5,6} 。为了更新候选项集的支持度计数,必须这样遍历 Hash 树:所有包含属于事务 t 的候选 3 -项集的叶结点至少访问一次。

注意:包含在t中的候选 3 -项集必须以项 1,2或3 开始,如上图中第一层前缀结构所示。这样,在Hash树的根结点,事务中的项 1,2 和 3 将分别散列。项 1 被散列到根结点的左子女,项 2 被散列到中间子女,而项 3 被散列到右子女。在树的下一层,事务根据上图中的第二层结构列出的第二项进行散列。

例如,在根结点散列项1之后,散列事务的项 2、3 和 5 。项 2 和 5 散列到中间子女,而 3 散列到右子女,如上图所示。继续该过程,直至到达 Hash 树的叶结点。存放在被访问的叶结点中的候选项集与事务进行比较,如果候选项集是该事务的子集,则增加它的支持度计数。在这个例子中,访问了 9 个叶结点中的 5 个, 15 个项集中的 9 个与事务进行比较。可以看到匹配过程只需要进行 11 次比较。

预期输出:

  1. ['1 3 5', '2 4', '1 2 3 4', '1 2', '2 3', '1 2', '2 3', '1 2 3 5', '1 2 3', '1 3 5']
  2. [['1'], ['3'], ['5'], ['2'], ['4']]
  3. {('1',): 7, ('3',): 7, ('5',): 3, ('2',): 8, ('4',): 2}
  4. All frequent itemsets with their support count:
  5. {('1',): 7, ('3',): 7, ('5',): 3, ('2',): 8, ('4',): 2, ('1', '3'): 5, ('1', '5'): 3, ('1', '2'): 5, ('3', '5'): 3, ('2', '3'): 5, ('2', '4'): 2, ('1', '3', '5'): 3, ('1', '2', '3'): 3}

注意:包含在t中的候选 3 -项集必须以项 1,2或3 开始,如上图中第一层前缀结构所示。这样,在Hash树的根结点,事务中的项 1,2 和 3 将分别散列。项 1 被散列到根结点的左子女,项 2 被散列到中间子女,而项 3 被散列到右子女。在树的下一层,事务根据上图中的第二层结构列出的第二项进行散列。

  1. import itertools
  2. import time
  3. filename = "data.csv"
  4. min_support = 2
  5. #读取数据集
  6. with open(filename) as f:
  7. content = f.readlines()
  8. content = [x.strip() for x in content]
  9. print(content)
  10. Transaction = [] #保存事务列表
  11. Frequent_items_value = {} #保存所有频繁项集字典
  12. #将数据集的内容添加到事物列表
  13. for i in range(0,len(content)):
  14. Transaction.append(content[i].split())
  15. #获得频繁一项集
  16. def frequent_one_item(Transaction,min_support):
  17. candidate1 = {}
  18. for i in range(0,len(Transaction)):
  19. for j in range(0,len(Transaction[i])):
  20. if Transaction[i][j] not in candidate1:
  21. candidate1[Transaction[i][j]] = 1
  22. else:
  23. candidate1[Transaction[i][j]] += 1
  24. frequentitem1 = [] #获得满足最小支持度的频繁一项集
  25. for value in candidate1:
  26. if candidate1[value] >= min_support:
  27. frequentitem1 = frequentitem1 + [[value]]
  28. Frequent_items_value[tuple(value)] = candidate1[value]
  29. return frequentitem1
  30. values = frequent_one_item(Transaction,min_support)
  31. print(values)
  32. print(Frequent_items_value)
  33. # 从事物中删除不频繁的一项集
  34. Transaction1 = []
  35. for i in range(0,len(Transaction)):
  36. list_val = []
  37. for j in range(0,len(Transaction[i])):
  38. if [Transaction[i][j]] in values:
  39. list_val.append(Transaction[i][j])
  40. Transaction1.append(list_val)
  41. #Hash节点类定义
  42. class Hash_node:
  43. def __init__(self):
  44. self.children = {} #指向子节点的指针
  45. self.Leaf_status = True #了解当前节点是否为叶子节点的状态
  46. self.bucket = {} #在储存桶中包含项目集
  47. #构造得到Hash树类
  48. class HashTree:
  49. # class constructor
  50. def __init__(self, max_leaf_count, max_child_count):
  51. self.root = Hash_node()
  52. self.max_leaf_count = max_leaf_count
  53. self.max_child_count = max_child_count
  54. self.frequent_itemsets = []
  55. # 进行递归插入以生成hashtree
  56. def recursively_insert(self, node, itemset, index, count):
  57. if index == len(itemset):
  58. if itemset in node.bucket:
  59. node.bucket[itemset] += count
  60. else:
  61. node.bucket[itemset] = count
  62. return
  63. if node.Leaf_status:
  64. ##########begin##########
  65. #如果node是叶结点所进行的操作代码
  66. if itemset in node.bucket:
  67. node.bucket[itemset]+=count
  68. else:
  69. node.bucket[itemset]=count
  70. if len(node.bucket)==self.max_leaf_count:
  71. 如果储存桶容量增加
  72. for old_itemset, old_count in node.bucket.items():
  73. hash_key = self.hash_function(old_itemset[index]) #对下一个索引做哈希
  74. if hash_key not in node.children:
  75. node.children[hash_key] = Hash_node()
  76. self.recursively_insert(node.children[hash_key], old_itemset, index + 1, old_count)
  77. del node.bucket
  78. node.Leaf_status = False
  79. ##########end##########
  80. else:
  81. ##########begin##########
  82. #如果node不是是叶结点所进行的操作代码
  83. hash_key=self.hash_function(itemset[index])
  84. if hash_key not in node.children:
  85. node.children[hash_key]=Hash_node()
  86. self.recursively_insert(node.children[hash_key],itemset,index+1,count)
  87. ##########end##########
  88. def insert(self, itemset):
  89. itemset = tuple(itemset)
  90. self.recursively_insert(self.root, itemset, 0, 0)
  91. # 添加支持度到候选项集中. 遍历树并找到该项集所在的储存桶.
  92. def add_support(self, itemset):
  93. Transverse_HNode = self.root
  94. itemset = tuple(itemset)
  95. index = 0
  96. while True:
  97. if Transverse_HNode.Leaf_status:
  98. if itemset in Transverse_HNode.bucket: #在此储存桶中找到项集
  99. Transverse_HNode.bucket[itemset] += 1 #增加此项目集的计数
  100. break
  101. hash_key = self.hash_function(itemset[index])
  102. if hash_key in Transverse_HNode.children:
  103. Transverse_HNode = Transverse_HNode.children[hash_key]
  104. else:
  105. break
  106. index += 1
  107. # 基于hash的支持度计算
  108. def get_frequent_itemsets(self, node, support_count,frequent_itemsets):
  109. ##########begin##########
  110. #获取频繁项集函数定义
  111. if node.Leaf_status:
  112. for key, value in node.bucket.items():
  113. if value >= support_count:
  114. #如果满足支持数条件
  115. frequent_itemsets.append(list(key))
  116. #将其添加到频繁项集中
  117. Frequent_items_value[key] = value
  118. for child in node.children.values():
  119. self.get_frequent_itemsets(child, support_count,frequent_itemsets)
  120. ##########end##########
  121. # hash function for making HashTree
  122. def hash_function(self, val):
  123. return int(val) % self.max_child_count
  124. #生成hashTree
  125. def generate_hash_tree(candidate_itemsets, max_leaf_count, max_child_count):
  126. htree = HashTree(max_child_count, max_leaf_count) #create instance of HashTree
  127. for itemset in candidate_itemsets:
  128. htree.insert(itemset) #to insert itemset into Hashtree
  129. return htree
  130. #to generate subsets of itemsets of size k
  131. def generate_k_subsets(dataset, length):
  132. subsets = []
  133. for itemset in dataset:
  134. subsets.extend(map(list, itertools.combinations(itemset, length)))
  135. return subsets
  136. def subset_generation(ck_data,l):
  137. return map(list,set(itertools.combinations(ck_data,l)))
  138. # 候选生成
  139. def apriori_generate(dataset,k):
  140. ck = []
  141. #join step
  142. lenlk = len(dataset)
  143. for i in range(lenlk):
  144. for j in range(i+1,lenlk):
  145. L1 = list(dataset[i])[:k - 2]
  146. L2 = list(dataset[j])[:k - 2]
  147. if L1 == L2:
  148. ck.append(sorted(list(set(dataset[i]) | set(dataset[j]))))
  149. #prune step
  150. final_ck = []
  151. for candidate in ck:
  152. all_subsets = list(subset_generation(set(candidate), k - 1))
  153. found = True
  154. for i in range(len(all_subsets)):
  155. value = list(sorted(all_subsets[i]))
  156. if value not in dataset:
  157. found = False
  158. if found == True:
  159. final_ck.append(candidate)
  160. return ck,final_ck
  161. # 候选剪枝
  162. def generateL(ck,min_support):
  163. support_ck = {}
  164. for val in Transaction1:
  165. for val1 in ck:
  166. value = set(val)
  167. value1 = set(val1)
  168. if value1.issubset(value):
  169. if tuple(val1) not in support_ck:
  170. support_ck[tuple(val1)] = 1
  171. else:
  172. support_ck[tuple(val1)] += 1
  173. frequent_item = []
  174. for item_set in support_ck:
  175. if support_ck[item_set] >= min_support:
  176. frequent_item.append(sorted(list(item_set)))
  177. Frequent_items_value[item_set] = support_ck[item_set]
  178. return frequent_item
  179. # apriori算法主函数
  180. def apriori(L1,min_support):
  181. k = 2;
  182. L = []
  183. L.append(0)
  184. L.append(L1)
  185. max_leaf_count = 6 #每个hash树节点的最大容量
  186. max_child_count = 6 #每个hash树节点的最大子节点数
  187. start = time.time()
  188. while(len(L[k-1])>0):
  189. ck,final_ck = apriori_generate(L[k-1],k) #生成候选项集
  190. # print("C%d" %(k))
  191. # print(final_ck)
  192. h_tree = generate_hash_tree(ck,max_leaf_count,max_child_count) #生成hash树
  193. if (k > 2):
  194. while(len(L[k-1])>0):
  195. l = generateL(final_ck, min_support)
  196. L.append(l)
  197. # print("Frequent %d item" % (k))
  198. # print(l)
  199. k = k + 1
  200. ck, final_ck = apriori_generate(L[k - 1], k)
  201. # print("C%d" % (k))
  202. # print(final_ck)
  203. break
  204. k_subsets = generate_k_subsets(Transaction1,k) #生成事物子集
  205. for subset in k_subsets:
  206. h_tree.add_support(subset) #像hash树的项集添加支持数
  207. lk = []
  208. h_tree.get_frequent_itemsets(h_tree.root,min_support,lk) #获取频繁项集
  209. # print("Frequent %d item" %(k))
  210. # print(lk)
  211. L.append(lk)
  212. k = k + 1
  213. end = time.time()
  214. return L,(end-start)
  215. L_value,time_taken = apriori(values,min_support)
  216. #print("final L_value")
  217. #print(L_value)
  218. print("All frequent itemsets with their support count:")
  219. print(Frequent_items_value)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/311634
推荐阅读
相关标签
  

闽ICP备14008679号