• 数据挖掘与机器学习:Apripori算法


    目录

    第一关:候选生成 

    任务描述:

    相关知识:

    一、Apripori算法候选生成:

    二、Apripori算法候选生成代码实现:

    编程要求:

    测试说明:

    第二关:候选剪枝

    任务描述:

    相关知识:

    Apripori算法候选剪枝:

    Apripori算法候选剪枝代码实现:

    编程要求:

    测试说明:

    第三关:基于遍历的支持度计算

    任务描述:

    相关知识:

    一、基于遍历的支持度计算:

    二、基于遍历的支持度计算代码实现:

    编程要求:

    测试说明:

    第四关:基于hash的支持度计算

    任务描述:

    相关知识:

    一、基于hash的支持度计算:

    二、基于hash的支持度计算代码实现:

    编程要求:

    测试说明:


    第一关:候选生成 

    任务描述:

     本关任务:编写一个能实现Apripori算法候选生成的小程序。

    相关知识:

     为了完成本关任务,你需要掌握:1.Apripori 算法候选生成,2.Apripori 算法候选生成代码实现。

    一、Apripori算法候选生成:

     Apripori算法利用自连接生成候选集:

    自连接:Lk​中的2个k项集l1​l2​,若l1​l2​有且仅有1个项不同,则将l1​l2​加入Ck+1​

    直观理解:生成可能的(k+1)项集:

     上图为频繁3项集L3​生成候选4项集C4​过程示例,可以看到L3​中的2个3项集ABCABD有且仅有1个项不同,则将 ABCABD=ABCD 加入C4​

    二、Apripori算法候选生成代码实现:

     Apripori 算法候选1项集生成函数如下:

    1. def create_c1(self, dataset): # 遍历整个数据集生成c1候选集
    2. c1 = set()
    3. for i in dataset:
    4. for j in i:
    5. item = frozenset([j])
    6. c1.add(item)
    7. return c1

    其中 dataset 为数据集列表。

    Apripori 算法候选 k 项集生成函数(无剪枝操作)代码思路如下:

    1. 创建Ck集合。
    2. 获取Lk_1的长度。
    3. 将Lk_1转换为列表。
    4. 两次遍历Lk-1,找出前n-1个元素相同的项。
    5. 只有最后一项不同时,生成下一候选项。
    6. 返回Ck集合。

    伪代码示例:

    1. def create_ck(self, Lk_1, size): # 通过频繁项集Lk-1创建ck候选项集
    2. Ck = set()
    3. l = len(Lk_1)
    4. lk_list = list(Lk_1)
    5. for i in range(l):
    6. for j in range(i + 1, l):
    7. # 两次遍历Lk-1,找出前n-1个元素相同的项
    8. # 只有最后一项不同时,生成下一候选项
    9. return Ck

    编程要求:

     根据提示,在右侧编辑器补充代码,生成候选3项集C3​

    测试说明:

    平台会对你编写的代码进行测试:

    预期输出:4

    1. class Apriori():
    2. def create_c1(self, dataset): # 遍历整个数据集生成c1候选集
    3. c1 = set()
    4. for i in dataset:
    5. for j in i:
    6. item = frozenset([j])
    7. c1.add(item)
    8. return c1
    9. def create_ck(self, Lk_1, size): # 通过频繁项集Lk-1创建ck候选项集
    10. Ck = set()
    11. l = len(Lk_1)
    12. lk_list = list(Lk_1)
    13. for i in range(l):
    14. for j in range(i + 1, l):
    15. ##########begin##########
    16. # 两次遍历Lk-1,找出前n-1个元素相同的项
    17. ##########end##########
    18. if l1[0:size - 2] == l2[0:size - 2]:
    19. ##########begin##########
    20. #只有最后一项不同时,生成下一候选项
    21. ##########end##########
    22. return Ck
    23. def generate_lk_by_ck_ergodic(self, data_set, ck, min_support, support_data):
    24. item_count = {}
    25. Lk = set()
    26. for t in data_set:
    27. for item in ck:
    28. if item.issubset(t):
    29. if item not in item_count:
    30. item_count[item] = 1
    31. else:
    32. item_count[item] += 1
    33. t_num = float(len(data_set))
    34. for item in item_count:
    35. if item_count[item] / t_num >= min_support:
    36. Lk.add(item)
    37. support_data[item] = item_count[item]
    38. return Lk
    39. if __name__ == "__main__":
    40. data = [['a','c','e'],['b','d'],['b','c'],['a','b','c','d'],['a','b'],['b','c'],['a','b'],
    41. ['a','b','c','e'],['a','b','c'],['a','c','e']]
    42. apriori = Apriori()
    43. support_data = {}
    44. c1 = apriori.create_c1(data)
    45. l1 = apriori.generate_lk_by_ck_ergodic(data_set=data, ck=c1, min_support=0.2, support_data=support_data)
    46. c2 = apriori.create_ck(l1, size=2)
    47. l2 = apriori.generate_lk_by_ck_ergodic(data_set=data, ck=c2, min_support=0.2, support_data=support_data)
    48. c3 = apriori.create_ck(l2, size=3)
    49. print(len(c3))

     

    通过代码:
     

    1. class Apriori():
    2. def create_c1(self, dataset): # 遍历整个数据集生成c1候选集
    3. c1 = set()
    4. for i in dataset:
    5. for j in i:
    6. item = frozenset([j])
    7. c1.add(item)
    8. return c1
    9. def create_ck(self, Lk_1, size): # 通过频繁项集Lk-1创建ck候选项集
    10. Ck = set()
    11. l = len(Lk_1)
    12. lk_list = list(Lk_1)
    13. for i in range(l):
    14. for j in range(i + 1, l):
    15. ##########begin##########
    16. # 两次遍历Lk-1,找出前n-1个元素相同的项
    17. l1 = list(lk_list[i])
    18.                 l2 = list(lk_list[j])
    19.                 l1.sort()
    20.                 l2.sort()
    21. ##########end##########
    22. if l1[0:size - 2] == l2[0:size - 2]:
    23. ##########begin##########
    24. #只有最后一项不同时,生成下一候选项
    25. Ck_item = lk_list[i] | lk_list[j]
    26.                     Ck.add(Ck_item)
    27. ##########end##########
    28. return Ck
    29. def generate_lk_by_ck_ergodic(self, data_set, ck, min_support, support_data):
    30. item_count = {}
    31. Lk = set()
    32. for t in data_set:
    33. for item in ck:
    34. if item.issubset(t):
    35. if item not in item_count:
    36. item_count[item] = 1
    37. else:
    38. item_count[item] += 1
    39. t_num = float(len(data_set))
    40. for item in item_count:
    41. if item_count[item] / t_num >= min_support:
    42. Lk.add(item)
    43. support_data[item] = item_count[item]
    44. return Lk
    45. if __name__ == "__main__":
    46. data = [['a','c','e'],['b','d'],['b','c'],['a','b','c','d'],['a','b'],['b','c'],['a','b'],
    47. ['a','b','c','e'],['a','b','c'],['a','c','e']]
    48. apriori = Apriori()
    49. support_data = {}
    50. c1 = apriori.create_c1(data)
    51. l1 = apriori.generate_lk_by_ck_ergodic(data_set=data, ck=c1, min_support=0.2, support_data=support_data)
    52. c2 = apriori.create_ck(l1, size=2)
    53. l2 = apriori.generate_lk_by_ck_ergodic(data_set=data, ck=c2, min_support=0.2, support_data=support_data)
    54. c3 = apriori.create_ck(l2, size=3)
    55. print(len(c3))

    第二关:候选剪枝

    任务描述:

     本关任务:编写一个能实现候选剪枝的小程序。

    相关知识:

    为了完成本关任务,你需要掌握:1.Apripori 算法候选剪枝,2.Apripori 算法候选剪枝代码实现。 

    Apripori算法候选剪枝:

    候选集的剪枝操作基于两个定理: 定理1:若某项集是频繁项集,则它的所有子集都是频繁项集。 例如:{a, b, c}是频繁项集,则{a}、{b}、{c}、{a, b}、{b, c}、{a, c}也是频繁项集。

    定理2:若某项集不是频繁项集,则它的所有超集都不是频繁项集。 例如:{a, b}不是频繁项集,则{a, b, c}也不是频繁项集。

    基于以上两个定理,我们需要对进行连接操作后的候选集进行剪枝操作,减小搜索空间。

    剪枝:Ck+1​ 中的某项集 c ,若 c 的某大小为 k 的子集 s 不存在于Lk​ ,则将 cCk+1 删除。

     上图为剪枝过程例图,蓝色表示项集在频繁3项集中,可以看到在生成的候选4项集 ABCE 中,其子集ABE 并不在频繁3项集中,所以剪枝删去。

    Apripori算法候选剪枝代码实现:

     剪枝的核心在于检查候选项集 Ck​ 的子集是否都在频繁项集 Lk−1​ 中。 检查函数主体如下:

    1. def has_infrequent_subset(self, Ck_item, Lk_1): # 检查候选项Ck_item的子集是否都在Lk-1中
    2. for item in Ck_item:
    3. sub_Ck = Ck_item - frozenset([item])
    4. #进行条件判断,如果存在候选项Ck_item子集不在Lk-1中则返回False
    5. return True

     在候选生成中添加剪枝伪代码示例:

    1. def create_ck(self, Lk_1, size): # 通过频繁项集Lk-1创建ck候选项集
    2. Ck = set()
    3. l = len(Lk_1)
    4. lk_list = list(Lk_1)
    5. for i in range(l):
    6. for j in range(i + 1, l):
    7. # 两次遍历Lk-1,找出前n-1个元素相同的项
    8. # 只有最后一项不同时,生成下一候选项
    9. # 检查该候选项的子集是否都在Lk-1中
    10. Ck.add(Ck_item)
    11. return Ck

    比起无剪枝的候选生成,多了一个判断该候选项的子集是否都在Lk-1中的条件判断。 

    编程要求:

    根据提示,在右侧编辑器补充代码,对生成的候选集剪枝。 

    测试说明:

    平台会对你编写的代码进行测试。

    预期输出:2

    1. class Apriori():
    2. def create_c1(self, dataset): # 遍历整个数据集生成c1候选集
    3. c1 = set()
    4. for i in dataset:
    5. for j in i:
    6. item = frozenset([j])
    7. c1.add(item)
    8. return c1
    9. def has_infrequent_subset(self, Ck_item, Lk_1):
    10. ##########begin##########
    11. # 检查候选项Ck_item的子集是否都在Lk-1中函数定义
    12. ##########end##########
    13. return True
    14. def create_ck(self, Lk_1, size): # 通过频繁项集Lk-1创建ck候选项集
    15. Ck = set()
    16. l = len(Lk_1)
    17. lk_list = list(Lk_1)
    18. for i in range(l):
    19. for j in range(i + 1, l):
    20. ##########begin##########
    21. # 两次遍历Lk-1,找出前n-1个元素相同的项
    22. ##########end##########
    23. if l1[0:size - 2] == l2[0:size - 2]:
    24. ##########begin##########
    25. #只有最后一项不同时,生成下一候选项
    26. #检查该候选项的子集是否都在Lk-1中
    27. ##########end##########
    28. return Ck
    29. def generate_lk_by_ck_ergodic(self, data_set, ck, min_support, support_data):
    30. item_count = {}
    31. Lk = set()
    32. for t in data_set:
    33. for item in ck:
    34. if item.issubset(t):
    35. if item not in item_count:
    36. item_count[item] = 1
    37. else:
    38. item_count[item] += 1
    39. t_num = float(len(data_set))
    40. for item in item_count:
    41. if item_count[item] / t_num >= min_support:
    42. Lk.add(item)
    43. support_data[item] = item_count[item]
    44. return Lk
    45. if __name__ == "__main__":
    46. data = [['a','c','e'],['b','d'],['b','c'],['a','b','c','d'],['a','b'],['b','c'],['a','b'],
    47. ['a','b','c','e'],['a','b','c'],['a','c','e']]
    48. apriori = Apriori()
    49. support_data = {}
    50. c1 = apriori.create_c1(data)
    51. l1 = apriori.generate_lk_by_ck_ergodic(data_set=data, ck=c1, min_support=0.2, support_data=support_data)
    52. c2 = apriori.create_ck(l1,size=2)
    53. l2 = apriori.generate_lk_by_ck_ergodic(data_set=data,ck=c2,min_support=0.2,support_data=support_data)
    54. c3 = apriori.create_ck(l2, size=3)
    55. print(len(c3))

    1. class Apriori():
    2. def create_c1(self, dataset): # 遍历整个数据集生成c1候选集
    3. c1 = set()
    4. for i in dataset:
    5. for j in i:
    6. item = frozenset([j])
    7. c1.add(item)
    8. return c1
    9. def has_infrequent_subset(self, Ck_item, Lk_1):
    10. ##########begin##########
    11. # 检查候选项Ck_item的子集是否都在Lk-1中函数定义
    12. for item in Ck_item:
    13.             sub_Ck = Ck_item - frozenset([item])
    14.             if sub_Ck not in Lk_1:
    15.                 return False
    16. ##########end##########
    17. return True
    18. def create_ck(self, Lk_1, size): # 通过频繁项集Lk-1创建ck候选项集
    19. Ck = set()
    20. l = len(Lk_1)
    21. lk_list = list(Lk_1)
    22. for i in range(l):
    23. for j in range(i + 1, l):
    24. ##########begin##########
    25. # 两次遍历Lk-1,找出前n-1个元素相同的项
    26. l1 = list(lk_list[i])
    27.                 l2 = list(lk_list[j])
    28.                 l1.sort()
    29.                 l2.sort()
    30. ##########end##########
    31. if l1[0:size - 2] == l2[0:size - 2]:
    32. ##########begin##########
    33. #只有最后一项不同时,生成下一候选项
    34. #检查该候选项的子集是否都在Lk-1中
    35. Ck_item = lk_list[i] | lk_list[j]
    36.                     if self.has_infrequent_subset(Ck_item, Lk_1):
    37.                         Ck.add(Ck_item)
    38. ##########end##########
    39. return Ck
    40. def generate_lk_by_ck_ergodic(self, data_set, ck, min_support, support_data):
    41. item_count = {}
    42. Lk = set()
    43. for t in data_set:
    44. for item in ck:
    45. if item.issubset(t):
    46. if item not in item_count:
    47. item_count[item] = 1
    48. else:
    49. item_count[item] += 1
    50. t_num = float(len(data_set))
    51. for item in item_count:
    52. if item_count[item] / t_num >= min_support:
    53. Lk.add(item)
    54. support_data[item] = item_count[item]
    55. return Lk
    56. if __name__ == "__main__":
    57. data = [['a','c','e'],['b','d'],['b','c'],['a','b','c','d'],['a','b'],['b','c'],['a','b'],
    58. ['a','b','c','e'],['a','b','c'],['a','c','e']]
    59. apriori = Apriori()
    60. support_data = {}
    61. c1 = apriori.create_c1(data)
    62. l1 = apriori.generate_lk_by_ck_ergodic(data_set=data, ck=c1, min_support=0.2, support_data=support_data)
    63. c2 = apriori.create_ck(l1,size=2)
    64. l2 = apriori.generate_lk_by_ck_ergodic(data_set=data,ck=c2,min_support=0.2,support_data=support_data)
    65. c3 = apriori.create_ck(l2, size=3)
    66. print(len(c3))

    第三关:基于遍历的支持度计算

    任务描述:

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

    相关知识:

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

    一、基于遍历的支持度计算:

     

    二、基于遍历的支持度计算代码实现:

     基于遍历的支持度计算函数如下:

    1. def generate_lk_by_ck_ergodic(self, data_set, ck, min_support, support_data): # 通过候选项ck生成lk,基于遍历的支持度计算并将各频繁项的支持度保存到support_data字典中
    2. item_count = {} # 用于标记各候选项在数据集出现的次数
    3. Lk = set()
    4. for t in tqdm(data_set): # 遍历数据集
    5. for item in ck:
    6. #检查候选集ck中的每一项是否出现在事务t中
    7. t_num = float(len(data_set))
    8. for item in item_count: # 将满足支持度的候选项添加到频繁项集中
    9. if item_count[item] / t_num >= min_support:
    10. Lk.add(item)
    11. support_data[item] = item_count[item]
    12. return Lk

     其中 data_set 为数据集,ck 为候选 k 项集,min_support为最小支持度, support_data 为各项的支持度记录字典。遍历数据集for循环中检查候选集ck中的每一项是否出现在事务t中请同学自行完成。

    编程要求:

    根据提示,在右侧编辑器补充代码,使用遍历计算支持度。 

    测试说明:

    平台会对你编写的代码进行测试:

    预期输出:6

    1. class Apriori():
    2. def create_c1(self, dataset): # 遍历整个数据集生成c1候选集
    3. c1 = set()
    4. for i in dataset:
    5. for j in i:
    6. item = frozenset([j])
    7. c1.add(item)
    8. return c1
    9. def create_ck(self, Lk_1, size): # 通过频繁项集Lk-1创建ck候选项集
    10. Ck = set()
    11. l = len(Lk_1)
    12. lk_list = list(Lk_1)
    13. for i in range(l):
    14. for j in range(i + 1, l): # 两次遍历Lk-1,找出前n-1个元素相同的项
    15. l1 = list(lk_list[i])
    16. l2 = list(lk_list[j])
    17. l1.sort()
    18. l2.sort()
    19. if l1[0:size - 2] == l2[0:size - 2]: # 只有最后一项不同时,生成下一候选项
    20. Ck_item = lk_list[i] | lk_list[j]
    21. if self.has_infrequent_subset(Ck_item, Lk_1): # 检查该候选项的子集是否都在Lk-1中
    22. Ck.add(Ck_item)
    23. return Ck
    24. def has_infrequent_subset(self, Ck_item, Lk_1): # 检查候选项Ck_item的子集是否都在Lk-1中
    25. for item in Ck_item:
    26. sub_Ck = Ck_item - frozenset([item])
    27. if sub_Ck not in Lk_1:
    28. return False
    29. return True
    30. def generate_lk_by_ck_ergodic(self, data_set, ck, min_support, support_data): # 通过候选项ck生成lk,基于遍历的支持度计算并将各频繁项的支持度保存到support_data字典中
    31. item_count = {} # 用于标记各候选项在数据集出现的次数
    32. Lk = set()
    33. # 基于遍历的支持度计算
    34. for t in data_set: # 遍历数据集
    35. for item in ck:
    36. ##########begin##########
    37. # 检查候选集ck中的每一项是否出现在事务t中
    38. ##########end##########
    39. t_num = float(len(data_set))
    40. for item in item_count:
    41. ##########begin##########
    42. # 将满足支持度的候选项添加到频繁项集中
    43. ##########end##########
    44. return Lk
    45. if __name__ == "__main__":
    46. data = [['a','c','e'],['b','d'],['b','c'],['a','b','c','d'],['a','b'],['b','c'],['a','b'],
    47. ['a','b','c','e'],['a','b','c'],['a','c','e']]
    48. apriori = Apriori()
    49. support_data = {}
    50. c1 = apriori.create_c1(data)
    51. l1 = apriori.generate_lk_by_ck_ergodic(data_set=data, ck=c1, min_support=0.2, support_data=support_data)
    52. c2 = apriori.create_ck(l1,size=2)
    53. l2 = apriori.generate_lk_by_ck_ergodic(data_set=data,ck=c2,min_support=0.2,support_data=support_data)
    54. print(len(l2))

     通过代码:

    1. class Apriori():
    2. def create_c1(self, dataset): # 遍历整个数据集生成c1候选集
    3. c1 = set()
    4. for i in dataset:
    5. for j in i:
    6. item = frozenset([j])
    7. c1.add(item)
    8. return c1
    9. def create_ck(self, Lk_1, size): # 通过频繁项集Lk-1创建ck候选项集
    10. Ck = set()
    11. l = len(Lk_1)
    12. lk_list = list(Lk_1)
    13. for i in range(l):
    14. for j in range(i + 1, l): # 两次遍历Lk-1,找出前n-1个元素相同的项
    15. l1 = list(lk_list[i])
    16. l2 = list(lk_list[j])
    17. l1.sort()
    18. l2.sort()
    19. if l1[0:size - 2] == l2[0:size - 2]: # 只有最后一项不同时,生成下一候选项
    20. Ck_item = lk_list[i] | lk_list[j]
    21. if self.has_infrequent_subset(Ck_item, Lk_1): # 检查该候选项的子集是否都在Lk-1中
    22. Ck.add(Ck_item)
    23. return Ck
    24. def has_infrequent_subset(self, Ck_item, Lk_1): # 检查候选项Ck_item的子集是否都在Lk-1中
    25. for item in Ck_item:
    26. sub_Ck = Ck_item - frozenset([item])
    27. if sub_Ck not in Lk_1:
    28. return False
    29. return True
    30. def generate_lk_by_ck_ergodic(self, data_set, ck, min_support, support_data): # 通过候选项ck生成lk,基于遍历的支持度计算并将各频繁项的支持度保存到support_data字典中
    31. item_count = {} # 用于标记各候选项在数据集出现的次数
    32. Lk = set()
    33. # 基于遍历的支持度计算
    34. for t in data_set: # 遍历数据集
    35. for item in ck:
    36. ##########begin##########
    37. # 检查候选集ck中的每一项是否出现在事务t中
    38. if item.issubset(t):
    39.                     if item not in item_count:
    40.                         item_count[item] = 1
    41.                     else:
    42.                         item_count[item] += 1
    43. ##########end##########
    44. t_num = float(len(data_set))
    45. for item in item_count:
    46. ##########begin##########
    47. # 将满足支持度的候选项添加到频繁项集中
    48.  if item_count[item] / t_num >= min_support:
    49.                 Lk.add(item)
    50.                 support_data[item] = item_count[item]
    51. ##########end##########
    52. return Lk
    53. if __name__ == "__main__":
    54. data = [['a','c','e'],['b','d'],['b','c'],['a','b','c','d'],['a','b'],['b','c'],['a','b'],
    55. ['a','b','c','e'],['a','b','c'],['a','c','e']]
    56. apriori = Apriori()
    57. support_data = {}
    58. c1 = apriori.create_c1(data)
    59. l1 = apriori.generate_lk_by_ck_ergodic(data_set=data, ck=c1, min_support=0.2, support_data=support_data)
    60. c2 = apriori.create_ck(l1,size=2)
    61. l2 = apriori.generate_lk_by_ck_ergodic(data_set=data,ck=c2,min_support=0.2,support_data=support_data)
    62. print(len(l2))

    第四关:基于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 个叶结点中。

    构建过程如下:

    给定一个事务 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 次比较。

    二、基于hash的支持度计算代码实现:

    基于 hash 的支持度计算关键在于 hash 树的构建。 首先构建节点类:

    1. #Hash节点类定义
    2. class Hash_node:
    3. def __init__(self):
    4. self.children = {} #指向子节点的指针
    5. self.Leaf_status = True #了解当前节点是否为叶子节点的状态
    6. self.bucket = {} #在储存桶中包含项目集

     然后构建hash树类:

    1. #构造得到Hash树类
    2. class HashTree:
    3. # class constructor
    4. def __init__(self, max_leaf_count, max_child_count):
    5. self.root = Hash_node()
    6. self.max_leaf_count = max_leaf_count
    7. self.max_child_count = max_child_count
    8. self.frequent_itemsets = []
    9. # 进行递归插入以生成hashtree
    10. def recursively_insert(self, node, itemset, index, count):
    11. if index == len(itemset):
    12. if itemset in node.bucket:
    13. node.bucket[itemset] += count
    14. else:
    15. node.bucket[itemset] = count
    16. return
    17. if node.Leaf_status: #如果node是叶结点
    18. if itemset in node.bucket:
    19. node.bucket[itemset] += count
    20. else:
    21. node.bucket[itemset] = count
    22. if len(node.bucket) == self.max_leaf_count: #如果储存桶容量增加
    23. for old_itemset, old_count in node.bucket.items():
    24. hash_key = self.hash_function(old_itemset[index]) #对下一个索引做哈希
    25. if hash_key not in node.children:
    26. node.children[hash_key] = Hash_node()
    27. self.recursively_insert(node.children[hash_key], old_itemset, index + 1, old_count)
    28. del node.bucket
    29. node.Leaf_status = False
    30. else:
    31. #如果node不是是叶结点
    32. #需要进行递归式的嵌入
    33. def insert(self, itemset):
    34. itemset = tuple(itemset)
    35. self.recursively_insert(self.root, itemset, 0, 0)
    36. # 添加支持度到候选项集中. 遍历树并找到该项集所在的储存桶.
    37. def add_support(self, itemset):
    38. Transverse_HNode = self.root
    39. itemset = tuple(itemset)
    40. index = 0
    41. while True:
    42. if Transverse_HNode.Leaf_status:
    43. if itemset in Transverse_HNode.bucket: #在此储存桶中找到项集
    44. Transverse_HNode.bucket[itemset] += 1 #增加此项目集的计数
    45. break
    46. hash_key = self.hash_function(itemset[index])
    47. if hash_key in Transverse_HNode.children:
    48. Transverse_HNode = Transverse_HNode.children[hash_key]
    49. else:
    50. break
    51. index += 1
    52. def get_frequent_itemsets(self, node, support_count,frequent_itemsets):
    53. if node.Leaf_status:
    54. for key, value in node.bucket.items():
    55. if value >= support_count: #如果满足支持数条件
    56. frequent_itemsets.append(list(key)) #将其添加到频繁项集中
    57. Frequent_items_value[key] = value
    58. return
    59. for child in node.children.values():
    60. self.get_frequent_itemsets(child, support_count,frequent_itemsets)
    61. # 用于构造hash树的hash函数定义
    62. def hash_function(self, val):
    63. return int(val) % self.max_child_count

    其中如果node不是叶结点,需要进行递归式的嵌入,请同学自行完成。
    提示:

    调用hash函数计算hash值。
    判断hash值是否在子节点中。
    如果不在就构建新节点。
    调用recursively_insert嵌入。

    编程要求:

     根据提示,在右侧编辑器补充代码,构造正确的hash树类实现hash的支持度计算。

    测试说明:

    平台会对你编写的代码进行测试:

    预期输出:

    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}

    开始你的任务吧,祝你成功!

    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. ##########end##########
    67. else:
    68. ##########begin##########
    69. #如果node不是是叶结点所进行的操作代码
    70. ##########end##########
    71. def insert(self, itemset):
    72. itemset = tuple(itemset)
    73. self.recursively_insert(self.root, itemset, 0, 0)
    74. # 添加支持度到候选项集中. 遍历树并找到该项集所在的储存桶.
    75. def add_support(self, itemset):
    76. Transverse_HNode = self.root
    77. itemset = tuple(itemset)
    78. index = 0
    79. while True:
    80. if Transverse_HNode.Leaf_status:
    81. if itemset in Transverse_HNode.bucket: #在此储存桶中找到项集
    82. Transverse_HNode.bucket[itemset] += 1 #增加此项目集的计数
    83. break
    84. hash_key = self.hash_function(itemset[index])
    85. if hash_key in Transverse_HNode.children:
    86. Transverse_HNode = Transverse_HNode.children[hash_key]
    87. else:
    88. break
    89. index += 1
    90. # 基于hash的支持度计算
    91. def get_frequent_itemsets(self, node, support_count,frequent_itemsets):
    92. ##########begin##########
    93. #获取频繁项集函数定义
    94. ##########end##########
    95. # hash function for making HashTree
    96. def hash_function(self, val):
    97. return int(val) % self.max_child_count
    98. #生成hashTree
    99. def generate_hash_tree(candidate_itemsets, max_leaf_count, max_child_count):
    100. htree = HashTree(max_child_count, max_leaf_count) #create instance of HashTree
    101. for itemset in candidate_itemsets:
    102. htree.insert(itemset) #to insert itemset into Hashtree
    103. return htree
    104. #to generate subsets of itemsets of size k
    105. def generate_k_subsets(dataset, length):
    106. subsets = []
    107. for itemset in dataset:
    108. subsets.extend(map(list, itertools.combinations(itemset, length)))
    109. return subsets
    110. def subset_generation(ck_data,l):
    111. return map(list,set(itertools.combinations(ck_data,l)))
    112. # 候选生成
    113. def apriori_generate(dataset,k):
    114. ck = []
    115. #join step
    116. lenlk = len(dataset)
    117. for i in range(lenlk):
    118. for j in range(i+1,lenlk):
    119. L1 = list(dataset[i])[:k - 2]
    120. L2 = list(dataset[j])[:k - 2]
    121. if L1 == L2:
    122. ck.append(sorted(list(set(dataset[i]) | set(dataset[j]))))
    123. #prune step
    124. final_ck = []
    125. for candidate in ck:
    126. all_subsets = list(subset_generation(set(candidate), k - 1))
    127. found = True
    128. for i in range(len(all_subsets)):
    129. value = list(sorted(all_subsets[i]))
    130. if value not in dataset:
    131. found = False
    132. if found == True:
    133. final_ck.append(candidate)
    134. return ck,final_ck
    135. # 候选剪枝
    136. def generateL(ck,min_support):
    137. support_ck = {}
    138. for val in Transaction1:
    139. for val1 in ck:
    140. value = set(val)
    141. value1 = set(val1)
    142. if value1.issubset(value):
    143. if tuple(val1) not in support_ck:
    144. support_ck[tuple(val1)] = 1
    145. else:
    146. support_ck[tuple(val1)] += 1
    147. frequent_item = []
    148. for item_set in support_ck:
    149. if support_ck[item_set] >= min_support:
    150. frequent_item.append(sorted(list(item_set)))
    151. Frequent_items_value[item_set] = support_ck[item_set]
    152. return frequent_item
    153. # apriori算法主函数
    154. def apriori(L1,min_support):
    155. k = 2;
    156. L = []
    157. L.append(0)
    158. L.append(L1)
    159. max_leaf_count = 6 #每个hash树节点的最大容量
    160. max_child_count = 6 #每个hash树节点的最大子节点数
    161. start = time.time()
    162. while(len(L[k-1])>0):
    163. ck,final_ck = apriori_generate(L[k-1],k) #生成候选项集
    164. # print("C%d" %(k))
    165. # print(final_ck)
    166. h_tree = generate_hash_tree(ck,max_leaf_count,max_child_count) #生成hash树
    167. if (k > 2):
    168. while(len(L[k-1])>0):
    169. l = generateL(final_ck, min_support)
    170. L.append(l)
    171. # print("Frequent %d item" % (k))
    172. # print(l)
    173. k = k + 1
    174. ck, final_ck = apriori_generate(L[k - 1], k)
    175. # print("C%d" % (k))
    176. # print(final_ck)
    177. break
    178. k_subsets = generate_k_subsets(Transaction1,k) #生成事物子集
    179. for subset in k_subsets:
    180. h_tree.add_support(subset) #像hash树的项集添加支持数
    181. lk = []
    182. h_tree.get_frequent_itemsets(h_tree.root,min_support,lk) #获取频繁项集
    183. # print("Frequent %d item" %(k))
    184. # print(lk)
    185. L.append(lk)
    186. k = k + 1
    187. end = time.time()
    188. return L,(end-start)
    189. L_value,time_taken = apriori(values,min_support)
    190. #print("final L_value")
    191. #print(L_value)
    192. print("All frequent itemsets with their support count:")
    193. print(Frequent_items_value)
    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. Frequent_items_value[key] = value
    117. return
    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)

  • 相关阅读:
    如何打造一个优秀的品牌?创立品牌的真正目的是什么?
    (附源码)ssm招聘网站 毕业设计 250858
    基于MYSQL的论坛管理系统数据库设计项目实战
    【iOS】—— 响应者链和事件传递链
    SQL优化--主键查询
    谷歌牛人发布小说式《算法图解》,竟被人扒下来,在GitHub开源了
    cmdline(二):uboot cmdline怎么传?&&cmdline kernel怎么用?
    编程前置:句子联想游戏
    Nginx 无法正确加载静态文件,静态文件加载404或者为html;Nginx 配置访问指定url路径项目部署;
    MySQL中如何识别低效的索引
  • 原文地址:https://blog.csdn.net/m0_58153897/article/details/127756637