浅谈Python实现Apriori算法介绍


Posted in Python onDecember 20, 2017

导读:

随着大数据概念的火热,啤酒与尿布的故事广为人知。我们如何发现买啤酒的人往往也会买尿布这一规律?数据挖掘中的用于挖掘频繁项集和关联规则的Apriori算法可以告诉我们。本文首先对Apriori算法进行简介,而后进一步介绍相关的基本概念,之后详细的介绍Apriori算法的具体策略和步骤,最后给出Python实现代码。

1.Apriori算法简介

Apriori算法是经典的挖掘频繁项集和关联规则的数据挖掘算法。A priori在拉丁语中指"来自以前"。当定义问题时,通常会使用先验知识或者假设,这被称作"一个先验"(a priori)。Apriori算法的名字正是基于这样的事实:算法使用频繁项集性质的先验性质,即频繁项集的所有非空子集也一定是频繁的。Apriori算法使用一种称为逐层搜索的迭代方法,其中k项集用于探索(k+1)项集。首先,通过扫描数据库,累计每个项的计数,并收集满足最小支持度的项,找出频繁1项集的集合。该集合记为L1。然后,使用L1找出频繁2项集的集合L2,使用L2找出L3,如此下去,直到不能再找到频繁k项集。每找出一个Lk需要一次数据库的完整扫描。Apriori算法使用频繁项集的先验性质来压缩搜索空间。

2. 基本概念

  1. 项与项集:设itemset={item1, item_2, …, item_m}是所有项的集合,其中,item_k(k=1,2,…,m)成为项。项的集合称为项集(itemset),包含k个项的项集称为k项集(k-itemset)。
  2. 事务与事务集:一个事务T是一个项集,它是itemset的一个子集,每个事务均与一个唯一标识符Tid相联系。不同的事务一起组成了事务集D,它构成了关联规则发现的事务数据库。
  3. 关联规则:关联规则是形如A=>B的蕴涵式,其中A、B均为itemset的子集且均不为空集,而A交B为空。
  4. 支持度(support):关联规则的支持度定义如下:

浅谈Python实现Apriori算法介绍

其中浅谈Python实现Apriori算法介绍表示事务包含集合A和B的并(即包含A和B中的每个项)的概率。注意与P(A or B)区别,后者表示事务包含A或B的概率。

置信度(confidence):关联规则的置信度定义如下:

浅谈Python实现Apriori算法介绍

项集的出现频度(support count):包含项集的事务数,简称为项集的频度、支持度计数或计数。

频繁项集(frequent itemset):如果项集I的相对支持度满足事先定义好的最小支持度阈值(即I的出现频度大于相应的最小出现频度(支持度计数)阈值),则I是频繁项集。

强关联规则:满足最小支持度和最小置信度的关联规则,即待挖掘的关联规则。

3. 实现步骤

一般而言,关联规则的挖掘是一个两步的过程:

  1. 找出所有的频繁项集
  2. 由频繁项集产生强关联规则

3.1挖掘频繁项集

3.1.1相关定义

连接步骤:频繁(k-1)项集Lk-1的自身连接产生候选k项集Ck

Apriori算法假定项集中的项按照字典序排序。如果Lk-1中某两个的元素(项集)itemset1和itemset2的前(k-2)个项是相同的,则称itemset1和itemset2是可连接的。所以itemset1与itemset2连接产生的结果项集是{itemset1[1], itemset1[2], …, itemset1[k-1], itemset2[k-1]}。连接步骤包含在下文代码中的create_Ck函数中。

剪枝策略

由于存在先验性质:任何非频繁的(k-1)项集都不是频繁k项集的子集。因此,如果一个候选k项集Ck的(k-1)项子集不在Lk-1中,则该候选也不可能是频繁的,从而可以从Ck中删除,获得压缩后的Ck。下文代码中的is_apriori函数用于判断是否满足先验性质,create_Ck函数中包含剪枝步骤,即若不满足先验性质,剪枝。

删除策略

基于压缩后的Ck,扫描所有事务,对Ck中的每个项进行计数,然后删除不满足最小支持度的项,从而获得频繁k项集。删除策略包含在下文代码中的generate_Lk_by_Ck函数中。

3.1.2 步骤

  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项集。

3.2 由频繁项集产生关联规则

一旦找出了频繁项集,就可以直接由它们产生强关联规则。产生步骤如下:

对于每个频繁项集itemset,产生itemset的所有非空子集(这些非空子集一定是频繁项集);

对于itemset的每个非空子集s,如果浅谈Python实现Apriori算法介绍,则输出浅谈Python实现Apriori算法介绍,其中min_conf是最小置信度阈值。

4. 样例以及Python实现代码

下图是《数据挖掘:概念与技术》(第三版)中挖掘频繁项集的样例图解。

浅谈Python实现Apriori算法介绍

本文基于该样例的数据编写Python代码实现Apriori算法。代码需要注意如下两点:

  1. 由于Apriori算法假定项集中的项是按字典序排序的,而集合本身是无序的,所以我们在必要时需要进行set和list的转换;
  2. 由于要使用字典(support_data)记录项集的支持度,需要用项集作为key,而可变集合无法作为字典的key,因此在合适时机应将项集转为固定集合frozenset。
"""
# Python 2.7
# Filename: apriori.py
# Author: llhthinker
# Email: hangliu56[AT]gmail[DOT]com
# Blog: http://www.cnblogs.com/llhthinker/p/6719779.html
# Date: 2017-04-16
"""


def load_data_set():
  """
  Load a sample data set (From Data Mining: Concepts and Techniques, 3th Edition)
  Returns: 
    A data set: A list of transactions. Each transaction contains several items.
  """
  data_set = [['l1', 'l2', 'l5'], ['l2', 'l4'], ['l2', 'l3'],
      ['l1', 'l2', 'l4'], ['l1', 'l3'], ['l2', 'l3'],
      ['l1', 'l3'], ['l1', 'l2', 'l3', 'l5'], ['l1', 'l2', 'l3']]
  return data_set


def create_C1(data_set):
  """
  Create frequent candidate 1-itemset C1 by scaning data set.
  Args:
    data_set: A list of transactions. Each transaction contains several items.
  Returns:
    C1: A set which contains all frequent candidate 1-itemsets
  """
  C1 = set()
  for t in data_set:
    for item in t:
      item_set = frozenset([item])
      C1.add(item_set)
  return C1


def is_apriori(Ck_item, Lksub1):
  """
  Judge whether a frequent candidate k-itemset satisfy Apriori property.
  Args:
    Ck_item: a frequent candidate k-itemset in Ck which contains all frequent
         candidate k-itemsets.
    Lksub1: Lk-1, a set which contains all frequent candidate (k-1)-itemsets.
  Returns:
    True: satisfying Apriori property.
    False: Not satisfying Apriori property.
  """
  for item in Ck_item:
    sub_Ck = Ck_item - frozenset([item])
    if sub_Ck not in Lksub1:
      return False
  return True


def create_Ck(Lksub1, k):
  """
  Create Ck, a set which contains all all frequent candidate k-itemsets
  by Lk-1's own connection operation.
  Args:
    Lksub1: Lk-1, a set which contains all frequent candidate (k-1)-itemsets.
    k: the item number of a frequent itemset.
  Return:
    Ck: a set which contains all all frequent candidate k-itemsets.
  """
  Ck = set()
  len_Lksub1 = len(Lksub1)
  list_Lksub1 = list(Lksub1)
  for i in range(len_Lksub1):
    for j in range(1, len_Lksub1):
      l1 = list(list_Lksub1[i])
      l2 = list(list_Lksub1[j])
      l1.sort()
      l2.sort()
      if l1[0:k-2] == l2[0:k-2]:
        Ck_item = list_Lksub1[i] | list_Lksub1[j]
        # pruning
        if is_apriori(Ck_item, Lksub1):
          Ck.add(Ck_item)
  return Ck


def generate_Lk_by_Ck(data_set, Ck, min_support, support_data):
  """
  Generate Lk by executing a delete policy from Ck.
  Args:
    data_set: A list of transactions. Each transaction contains several items.
    Ck: A set which contains all all frequent candidate k-itemsets.
    min_support: The minimum support.
    support_data: A dictionary. The key is frequent itemset and the value is support.
  Returns:
    Lk: A set which contains all all frequent k-itemsets.
  """
  Lk = set()
  item_count = {}
  for t in data_set:
    for item in Ck:
      if item.issubset(t):
        if item not in item_count:
          item_count[item] = 1
        else:
          item_count[item] += 1
  t_num = float(len(data_set))
  for item in item_count:
    if (item_count[item] / t_num) >= min_support:
      Lk.add(item)
      support_data[item] = item_count[item] / t_num
  return Lk


def generate_L(data_set, k, min_support):
  """
  Generate all frequent itemsets.
  Args:
    data_set: A list of transactions. Each transaction contains several items.
    k: Maximum number of items for all frequent itemsets.
    min_support: The minimum support.
  Returns:
    L: The list of Lk.
    support_data: A dictionary. The key is frequent itemset and the value is support.
  """
  support_data = {}
  C1 = create_C1(data_set)
  L1 = generate_Lk_by_Ck(data_set, C1, min_support, support_data)
  Lksub1 = L1.copy()
  L = []
  L.append(Lksub1)
  for i in range(2, k+1):
    Ci = create_Ck(Lksub1, i)
    Li = generate_Lk_by_Ck(data_set, Ci, min_support, support_data)
    Lksub1 = Li.copy()
    L.append(Lksub1)
  return L, support_data


def generate_big_rules(L, support_data, min_conf):
  """
  Generate big rules from frequent itemsets.
  Args:
    L: The list of Lk.
    support_data: A dictionary. The key is frequent itemset and the value is support.
    min_conf: Minimal confidence.
  Returns:
    big_rule_list: A list which contains all big rules. Each big rule is represented
            as a 3-tuple.
  """
  big_rule_list = []
  sub_set_list = []
  for i in range(0, len(L)):
    for freq_set in L[i]:
      for sub_set in sub_set_list:
        if sub_set.issubset(freq_set):
          conf = support_data[freq_set] / support_data[freq_set - sub_set]
          big_rule = (freq_set - sub_set, sub_set, conf)
          if conf >= min_conf and big_rule not in big_rule_list:
            # print freq_set-sub_set, " => ", sub_set, "conf: ", conf
            big_rule_list.append(big_rule)
      sub_set_list.append(freq_set)
  return big_rule_list


if __name__ == "__main__":
  """
  Test
  """
  data_set = load_data_set()
  L, support_data = generate_L(data_set, k=3, min_support=0.2)
  big_rules_list = generate_big_rules(L, support_data, min_conf=0.7)
  for Lk in L:
    print "="*50
    print "frequent " + str(len(list(Lk)[0])) + "-itemsets\t\tsupport"
    print "="*50
    for freq_set in Lk:
      print freq_set, support_data[freq_set]
  print
  print "Big Rules"
  for item in big_rules_list:
    print item[0], "=>", item[1], "conf: ", item[2]

代码运行结果截图如下:

浅谈Python实现Apriori算法介绍

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
用Python的pandas框架操作Excel文件中的数据教程
Mar 31 Python
Python实现的异步代理爬虫及代理池
Mar 17 Python
python 计算两个日期相差多少个月实例代码
May 24 Python
Python读取系统文件夹内所有文件并统计数量的方法
Oct 23 Python
Python数据可视化之画图
Jan 15 Python
python 实现多线程下载视频的代码
Nov 15 Python
python的json中方法及jsonpath模块用法分析
Dec 06 Python
Python 实现opencv所使用的图片格式与 base64 转换
Jan 09 Python
在服务器上安装python3.8.2环境的教程详解
Apr 26 Python
Python中实现输入一个整数的案例
May 03 Python
Python Socket TCP双端聊天功能实现过程详解
Jun 15 Python
tensorflow基于CNN实战mnist手写识别(小白必看)
Jul 20 Python
利用Python如何生成hash值示例详解
Dec 20 #Python
python 3.6 tkinter+urllib+json实现火车车次信息查询功能
Dec 20 #Python
python实现神经网络感知器算法
Dec 20 #Python
Python代码实现KNN算法
Dec 20 #Python
详解appium+python 启动一个app步骤
Dec 20 #Python
浅谈Django自定义模板标签template_tags的用处
Dec 20 #Python
Python实现感知机(PLA)算法
Dec 20 #Python
You might like
DC动画很好看?新作烂得令人发指,名叫《红色之子》
2020/04/09 欧美动漫
PHP4实际应用经验篇(5)
2006/10/09 PHP
php 中include()与require()的对比
2006/10/09 PHP
PHP 伪静态隐藏传递参数名的四种方法
2010/02/22 PHP
php数据类型判断函数有哪些
2013/09/23 PHP
php动态变量定义及使用
2015/06/10 PHP
PHP微信开发之模板消息回复
2016/06/24 PHP
ExtJS扩展 垂直tabLayout实现代码
2009/06/21 Javascript
jQuery点缩略图弹出层显示大图片
2015/02/13 Javascript
jQuery Timelinr实现垂直水平时间轴插件(附源码下载)
2016/02/16 Javascript
全面解析标签页的切换方式
2016/08/21 Javascript
vue-router 学习快速入门
2017/03/01 Javascript
jQuery事件委托代码实践详解
2019/06/21 jQuery
解决Vue 移动端点击出现300毫秒延迟的问题
2020/07/21 Javascript
JavaScript实现京东快递单号查询
2020/11/30 Javascript
jQuery实现鼠标拖动图片功能
2021/03/04 jQuery
python UNIX_TIMESTAMP时间处理方法分析
2016/04/18 Python
Python的地形三维可视化Matplotlib和gdal使用实例
2017/12/09 Python
详解django三种文件下载方式
2018/04/06 Python
Python实现读取机器硬件信息的方法示例
2018/06/09 Python
Anaconda2 5.2.0安装使用图文教程
2018/09/19 Python
Django 项目重命名的实现步骤解析
2019/08/14 Python
python实现单机五子棋
2020/08/28 Python
一款纯css3实现的非常实用的鼠标悬停特效演示
2014/11/05 HTML / CSS
HTML5实现表单自动验证功能实例代码
2017/01/11 HTML / CSS
英国最大的宠物食品和宠物用品网上零售商: Zooplus
2016/08/01 全球购物
华为慧通面试题
2012/09/11 面试题
写好自荐信的要点
2013/11/06 职场文书
工程质量承诺书
2014/03/27 职场文书
白莲教口号
2014/06/18 职场文书
公共场所禁烟标语
2014/06/25 职场文书
银行职员工作失误检讨书
2014/10/14 职场文书
初中班主任工作随笔
2015/08/15 职场文书
golang通过递归遍历生成树状结构的操作
2021/04/28 Golang
golang内置函数len的小技巧
2021/07/25 Golang
SpringBoot项目多数据源及mybatis 驼峰失效的问题解决方法
2022/07/07 Java/Android