机器学习实战(Machine Learning in Action)学习笔记————07.使用Apriori算法进行关联分析

关键字:Apriori、关联规则挖掘、频繁项集
作者:米仓山下
时间:2018-11-2
机器学习实战(Machine Learning in Action,@author: Peter Harrington)
源码下载地址:https://www.manning.com/books/machine-learning-in-action
git@github.com:pbharrin/machinelearninginaction.git

*************************************************************
一、Apriori算法——生成频繁项集

Apriori算法原理:
原理:如果某个项集是频繁的,那么它所有的子集也是频繁的。反过来,如果一个项集是非频繁集,那么他所有的超集也是非频繁的
--------------------------------------------------------------
#创建测试数据集,包含四个列表的列表:[[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
loadDataSet()
#根据测试数据集生成第一个频繁项集,频繁项为单个
createC1(dataSet)
#根据给定的频繁项集Ck,支持度minSupport,计算在数据集D中Ck各频繁项的支持度,并返回支持度大于minSupport的频繁项(数组),及所有频繁项的支持度(频繁项为key,支持度为value的字典)
scanD(D, Ck, minSupport)
--------------------------------------------------------------
#根据给定频繁项集生成下Lk,通过集合并集运算,得到频繁项集Lk+1。

def aprioriGen(Lk, k): #creates Ck
retList = []
lenLk = len(Lk)
for i in range(lenLk):
for j in range(i+1, lenLk):
L1 = list(Lk[i])[:k-2]; L2 = list(Lk[j])[:k-2]
L1.sort(); L2.sort()
if L1==L2: #if first k-2 elements are equal
retList.append(Lk[i] | Lk[j]) #set union
return retList

#注:这里强调一下为什么只比较前k-2元素,书中强调的原因是可以减少循环次数,但并没有进一步解释这样做的逻辑。示例数据中,两项的频繁项集为[{2,3}, {3,5}, {2,5}, {1,3}],所有两两并集为[{2,3,5},{1,3,5}]。但是如果仅比较前k-2个元素相同的进行合并为[{2,3,5}],之所以没有{1,3,5}是因为{1,5}不存在,即它不是频繁项集,按照Apriori的原理“某个子项集不是频繁的,那么它的超集也不是频繁的”。因此比较前k-2个元素既可以减少循环次数又不会漏掉频繁项。

--------------------------------------------------------------
#不断扫描数据集,由单元素频繁项不断合并,并求解它们的支持度,记录下符合条件的频繁项,以及频繁项的支持度

def apriori(dataSet, minSupport = 0.5):
C1 = createC1(dataSet) #生成单元素频繁项集
D = map(set, dataSet)
L1, supportData = scanD(D, C1, minSupport) #计算单元素频繁项集的支持度,并筛选
L = [L1]
k = 2
while (len(L[k-2]) > 0): #当最加入新频繁项集长度大于零
Ck = aprioriGen(L[k-2], k) #合并频繁项集形成新的候选集
Lk, supK = scanD(D, Ck, minSupport) #计算候选集的支持度,并筛选
supportData.update(supK) #更新存储频繁项支持度的词典
L.append(Lk) #将最新得到的频繁项加入列表中
k += 1
return L, supportData

--------------------------------------------------------------
测试:

>>> import apriori
>>> data=apriori.loadDataSet()
>>> data
[[, , ], [, , ], [, , , ], [, ]]
>>> L,supportData=apriori.apriori(data)
>>> L
[[frozenset([]), frozenset([]), frozenset([]), frozenset([])], [frozenset([, ]), frozenset([, ]), frozenset([, ]), frozenset([, ])], [frozenset([, , ])], []]
>>> supportData
{frozenset([]): 0.75, frozenset([]): 0.75, frozenset([, , ]): 0.5, frozenset([, ]): 0.25, frozenset([, ]): 0.25, frozenset([, ]): 0.5, frozenset([]): 0.25, frozenset([, ]): 0.5, frozenset([, ]): 0.75, frozenset([]): 0.5, frozenset([, ]): 0.5, frozenset([]): 0.75}
>>>

*************************************************************
二、Apriori算法——从频繁项集中挖掘关联规则

置信度:
  置信度(confidence)揭示了A出现时B是否一定出现,如果出现,则出现的概率是多大。如果A->B的置信度是100%,则说明A出现时B一定会出现(返回来不一定)。用公式表示是,物品A->B的置信度=物品{A,B}的支持度 / 物品{A}的支持度:(A称为前件,B称为后件)
Confidence(A->B) = support({A,B}) / support({A}) = P(B|A)

如果某条规则不满足最小可信度要求,那么该规则的所有子集也不会满足最小置信度要求。假设{0,1,2}->{3}不满足最小可信度的要求。那么任何{0,1,2}的子集也不会满足最小可信度的要求。可以利用该性质来减少需要测试的规则数目。

--------------------------------------------------------------
#规则生成函数

def generateRules(L, supportData, minConf=0.7):  #supportData is a dict coming from scanD
bigRuleList = [] #存储关联规则的列表
for i in range(1, len(L)): #取出两个或更多元素的频繁项集,L[0]为单元素频繁项集,遍历
for freqSet in L[i]: #遍历频繁项集L[i]中的频繁项
H1 = [frozenset([item]) for item in freqSet] #某个频繁项中的元素列表
if (i > 1): #元素大于两个的频繁项,将频繁项中的元素进行组合成后件(规则)
rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
else: #i=1,两个元素的频繁项
calcConf(freqSet, H1, supportData, bigRuleList, minConf)
return bigRuleList

--------------------------------------------------------------
#计算可信度
#输入:freqSet——频繁项, H——频繁项元素列表, supportData——频繁项支持度列表, brl——存储关联规则的列表, minConf——最小可信度
#输出:brl——频繁项freqSet中存在的关联规则,prunedH——返回关联规则中的后件列表

def calcConf(freqSet, H, supportData, brl, minConf=0.7):
prunedH = [] #关联规则中的后件列表
for conseq in H: #遍历频繁项中的元素,conseq为元素
conf = supportData[freqSet]/supportData[freqSet-conseq] #可信度(freq-conseq)->conseq
if conf >= minConf: #可信度>minConf
print freqSet-conseq,'-->',conseq,'conf:',conf #打印关联规则及可信度
brl.append((freqSet-conseq, conseq, conf)) #保存关联规则及可信度
prunedH.append(conseq) #保存后件(规则),为后面准备。注:不满足规则的后件,在该元素基础下添加也不会满足
return prunedH

--------------------------------------------------------------
#最初的规则生成更多的规则
#输入:freqSet——频繁项, H——频繁项元素列表;输出:brl——频繁项freqSet中存在的关联规则

def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
m = len(H[0])
if (len(freqSet) > (m + 1)): #频繁项元素数目>后件(候选规则)的元素数,一直执行。例如{1,2,3,4}当{1}-{2,3,4}以后此时H[0]长度为3
Hmp1 = aprioriGen(H, m+1) #合并候选后件(规则),由Hm生成Hm+1。注:不满足规则的后件,在该元素基础下添加也不会满足
Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf) #返回规则后件(规则)列表
if (len(Hmp1) > 1): #返回后件(规则)列表包含1个以上后件(规则),递归进一步组合这些规则
rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)

--------------------------------------------------------------
测试:

>>> reload(apriori)
<module 'apriori' from 'apriori.py'>
>>> L, supportData=apriori.apriori(data)
>>> L
[[frozenset([1]), frozenset([3]), frozenset([2]), frozenset([5])], [frozenset([1, 3]), frozenset([2, 5]), frozenset([2, 3]), frozenset([3, 5])], [frozenset([2, 3, 5])], []]
>>> supportData
{frozenset([5]): 0.75, frozenset([3]): 0.75, frozenset([2, 3, 5]): 0.5, frozenset([1, 2]): 0.25, frozenset([1, 5]): 0.25, frozenset([3, 5]): 0.5, frozenset([4]): 0.25, frozenset([2, 3]): 0.5, frozenset([2, 5]): 0.75, frozenset([1]): 0.5, frozenset([1, 3]): 0.5, frozenset([2]): 0.75}
>>> rules=generateRules(L, supportData, minConf=0.6)
frozenset([3]) --> frozenset([1]) conf: 0.666666666667
frozenset([1]) --> frozenset([3]) conf: 1.0
frozenset([5]) --> frozenset([2]) conf: 1.0
frozenset([2]) --> frozenset([5]) conf: 1.0
frozenset([3]) --> frozenset([2]) conf: 0.666666666667
frozenset([2]) --> frozenset([3]) conf: 0.666666666667
frozenset([5]) --> frozenset([3]) conf: 0.666666666667
frozenset([3]) --> frozenset([5]) conf: 0.666666666667
frozenset([5]) --> frozenset([2, 3]) conf: 0.666666666667
frozenset([3]) --> frozenset([2, 5]) conf: 0.666666666667
frozenset([2]) --> frozenset([3, 5]) conf: 0.666666666667
>>>
>>> rules=generateRules(L, supportData, minConf=0.7)
frozenset([1]) --> frozenset([3]) conf: 1.0 #出现1集合中一定出现了3
frozenset([5]) --> frozenset([2]) conf: 1.0 #出现5集合中一定出现了2
frozenset([2]) --> frozenset([5]) conf: 1.0 #出现2集合中一定出现了5
>>>
>>> rules
[(frozenset([1]), frozenset([3]), 1.0), (frozenset([5]), frozenset([2]), 1.0), (frozenset([2]), frozenset([5]), 1.0)]
>>>

*************************************************************
三、示例:发现毒蘑菇的相似特征
数据集:mushroom.dat
说明:mushroom数据集是关于肋形蘑菇的23种特征的数据集,每个特征都包含一个标称数据值。
mushroom.dat前几列数据为:
1 3 9 13 23 25 34 36 38 40 52 54 59 63 67 76 85 86 90 93 98 107 113
2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114
2 4 9 15 23 27 34 36 39 41 52 55 59 63 67 76 85 86 90 93 99 108 115
第一个特征表示有毒(2)或则可食用(1),下一特征为蘑菇伞的形状,六种可能的值3-8表示。

#将数据读取转换为集合
>>> mushDataSet=[line.split() for line in open('mushroom.dat').readlines()]
>>> mushDataSet[0]
['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
>>> len(mushDataSet)
8124 #生成频繁项集
>>> L, supportData=apriori.apriori(mushDataSet,minSupport = 0.3)
>>> len(L)
10
>>> L[9]
[]
>>> L[8]
[frozenset(['', '', '', '', '', '', '', '', '']), frozenset(['', '', '', '', '', '', '', '', '']), frozenset(['', '', '', '', '', '', '', '', '']), frozenset(['', '', '', '', '', '', '', '', ''])]
>>> #所有特征的标称性数值并不重复,打印长度为8的所有有毒(2)的频繁项
>>> for item in L[7]:
... if item.intersection(''):print item
...
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
frozenset(['', '', '', '', '', '', '', ''])
>>>

#这样就可以看到有哪些特征的蘑菇大概率是毒蘑菇。但:并不表示没有这些特诊的蘑菇就没有毒

*************************************************************
四、总结
关联分析用于发现大规模数据集中元素间有趣关系。通过两种两种方式量化这些有趣关系:第一种是使用频繁项集,给出经常一起出现的元素项;第二种是关联规则,每条关联规则意味着元素之间“如果……那么”的关系。

减少扫描频繁项统计扫描次数的方法就是Apriori。Apriori原理是说如果一个元素项是不频繁的那么包含该元素的超集也是不频繁的。Apriori算法从单元素项集合开始,通过组合满足最小支持度要求的项集来形成更大的集合。支持度用来度量一个集合在原始数据中出现的频率。

原始数据中每条数据是集合,但并不要求每条数据具有相同的长度

缺点:每次增加频繁项集的大小,Apriori算法都会扫描整个数据集。数据集很大时会降低频繁项集发现的速度。相比,12章中FPgrowth算法只需要对数据库进行两次扫描,能够显著加快频繁项集发现速度

参考文献:
https://blog.csdn.net/wanghao109/article/details/39452303
https://www.cnblogs.com/bigmonkey/p/7405555.html
https://blog.csdn.net/zllnau66/article/details/81534368

机器学习实战(Machine Learning in Action)学习笔记————07.使用Apriori算法进行关联分析的更多相关文章

  1. 机器学习实战 - 读书笔记(11) - 使用Apriori算法进行关联分析

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第11章 - 使用Apriori算法进行关联分析. 基本概念 关联分析(associat ...

  2. 机器学习实战 [Machine learning in action]

    内容简介 机器学习是人工智能研究领域中一个极其重要的研究方向,在现今的大数据时代背景下,捕获数据并从中萃取有价值的信息或模式,成为各行业求生存.谋发展的决定性手段,这使得这一过去为分析师和数学家所专属 ...

  3. 学习笔记之机器学习实战 (Machine Learning in Action)

    机器学习实战 (豆瓣) https://book.douban.com/subject/24703171/ 机器学习是人工智能研究领域中一个极其重要的研究方向,在现今的大数据时代背景下,捕获数据并从中 ...

  4. K近邻 Python实现 机器学习实战(Machine Learning in Action)

    算法原理 K近邻是机器学习中常见的分类方法之间,也是相对最简单的一种分类方法,属于监督学习范畴.其实K近邻并没有显式的学习过程,它的学习过程就是测试过程.K近邻思想很简单:先给你一个训练数据集D,包括 ...

  5. 【机器学习实战】第11章 使用 Apriori 算法进行关联分析

    第 11 章 使用 Apriori 算法进行关联分析 关联分析 关联分析是一种在大规模数据集中寻找有趣关系的任务. 这些关系可以有两种形式: 频繁项集(frequent item sets): 经常出 ...

  6. Coursera 机器学习 第6章(下) Machine Learning System Design 学习笔记

    Machine Learning System Design下面会讨论机器学习系统的设计.分析在设计复杂机器学习系统时将会遇到的主要问题,给出如何巧妙构造一个复杂的机器学习系统的建议.6.4 Buil ...

  7. 【python与机器学习实战】感知机和支持向量机学习笔记(一)

    对<Python与机器学习实战>一书阅读的记录,对于一些难以理解的地方查阅了资料辅以理解并补充和记录,重新梳理一下感知机和SVM的算法原理,加深记忆. 1.感知机 感知机的基本概念 感知机 ...

  8. 机器学习——使用Apriori算法进行关联分析

    从大规模的数据集中寻找隐含关系被称作为关联分析(association analysis)或者关联规则学习(association rule learning). Apriori算法 优点:易编码实现 ...

  9. Machine Learning(Andrew Ng)学习笔记

    1.监督学习(supervised learning)&非监督学习(unsupervised learning) 监督学习:处理具有若干属性且返回值不同的对象.分为回归型和分类型:回归型的返回 ...

随机推荐

  1. C# 获取所有对象的字符串表示一ToString方法

    应用程序开发过程中经常需要获取对象的字符串表示.Object类中定义了一个ToString的虚方法.所以在任何类型的实例上都能调用该方法. C#中几乎所有的类型都派生自Object,所以如果当前类型没 ...

  2. solr(二) : 整合ik-analyzer

    一. 问题: 在使用solr时, 分词器解析中文的时候, 是一个一个字解析的. 这并不是我们想要的结果. 而在lucene中, 使用的中文分词器是 IKAnalyzer. 那么在solr里面, 是不是 ...

  3. 面试:用快排实现数组中的第K大的数

    #include <iostream> #include <cassert> using namespace std; int selectKth(int a[],int st ...

  4. Tomcat学习总结(13)—— Tomcat常用参数配置说明

    1.修改端口号 Tomcat端口配置在server.xml文件的Connector标签中,默认为8080,可根据实际情况修改. 修改端口号 2.解决URL中文参数乱码 在server.xml文件的Co ...

  5. 自我总结(四) ---java web项目完结,j2ee的开始

    自我完善的过程就是在不断的自我总结不断的改进. 前半个月刚好把项目做完了,项目也答辩了.总的来说吧,我觉得自己在java web这块知识上不算是彻彻底底把他弄懂了,就是说到的知识点都能够回答的上来一些 ...

  6. keepalived之单播----k8sHA准备

    一.概述 keepalived主要有三个模块,分别是core.check和vrrp.core模块为keepalived的核心,负责主进程的启动.维护以及全局配置文件的加载和解析.check负责健康检查 ...

  7. spring StopWatch用法

    背景 有时我们在做开发的时候需要记录每个任务执行时间,或者记录一段代码执行时间,最简单的方法就是打印当前时间与执行完时间的差值,然后这样如果执行大量测试的话就很麻烦,并且不直观,如果想对执行的时间做进 ...

  8. nodejs 的序列化与反序列化

    1.序列化 stringify函数的作用就是序列化对象,也就是说将对象类型转换成一个字符串类型(默认的分割符("&")和分配符("=")),先介绍它的基 ...

  9. 如何给oracle账户解锁

    在创建数据库时,已经为SYS等4个账户设定了口令,其中SYS与SYSTEM具有管理员权限,在SQL*Plus工具中使用SYSTEM账户登录Oracle数据库. 1.通过数据字典dba_users,查看 ...

  10. Java多线程--JDK并发包(2)

    Java多线程--JDK并发包(2) 线程池 在使用线程池后,创建线程变成了从线程池里获得空闲线程,关闭线程变成了将线程归坏给线程池. JDK有一套Executor框架,大概包括Executor.Ex ...