mirror of
https://github.com/apachecn/ailearning.git
synced 2026-05-08 06:33:55 +08:00
Merge pull request #60 from jiangzhonglian/master
更新完:11.Apriori算法注释和文档
This commit is contained in:
@@ -1,16 +1,14 @@
|
||||
|
||||
# 11) 使用Apriori算法进行关联分析
|
||||
|
||||
* 使用场景:
|
||||
* 用户去超市、电商平台去买东西;那么是否可以促进用户消费呢?
|
||||
* 目的:商店希望从客户身上获取尽可能多的利润。
|
||||
* 忠诚度计划: 通过顾客的会员卡可获取已定的折扣,商店也可以了解客户购买的商品; 不买会员卡,商店也可以查用顾客一起购买的物品,找出商品之间的关系。
|
||||
* 例如: 尿布和啤酒的故事
|
||||
* 关联关系(associati analysis) 或 关联规则学习(association rule learning)
|
||||
* 从大规模数据集中寻找物品间的隐含关系呗称作关联关系。
|
||||
* 从大规模数据集中寻找物品间的隐含关系被称作关联关系。
|
||||
* 关联分析:
|
||||
* 优点:易编码实现
|
||||
* 缺点:在大数据集上可能较慢
|
||||
* 适用数据类型:数值型 或者 标称型数据。
|
||||
* 概念:是一种在大规模数据集中寻找有趣关系的任务。
|
||||
* 关联分析有2种形式:
|
||||
* 1.频繁项集(frequent item sets): 经常出现在一块的物品集合
|
||||
* 2.关联规则(association rules): 暗示两种物品之间可能存在很强的关系
|
||||
@@ -23,6 +21,17 @@
|
||||
* 置信度(confidence)
|
||||
* 置信度({A}->{B}) = 支持度{A,B}/支持度{A}
|
||||
* 例如上图中:{尿布,葡萄酒}的支持度=3/5, {尿布}的支持度=4/5, 所以 尿布->葡萄酒的可信度=3/4
|
||||
* Apriori算法
|
||||
* 优点:易编码实现
|
||||
* 缺点:在大数据集上可能较慢
|
||||
* 适用数据类型:数值型 或者 标称型数据。
|
||||
* Apriori流程步骤:
|
||||
* 收集数据:使用任意方法。
|
||||
* 准备数据:任何数据类型都可以,因为我们只保存集合。
|
||||
* 分析数据:使用任意方法。
|
||||
* 训练数据:使用Apiori算法来找到频繁项集。
|
||||
* 测试算法:不需要测试过程。
|
||||
* 使用算法:用语发现频繁项集以及物品之间的关联规则。
|
||||
* Apriori原理
|
||||
* 如果某个项集是频繁的,那么它的所有子集也是频繁的,反之,一个项集是非频繁的,那么它的所有超集也是非频繁的。
|
||||
* 例如: 我们假设知道{2, 3}是非频繁项,那么{0, 2, 3}, {1, 2, 3}, {0, 1, 2, 3}都是非频繁项。
|
||||
|
||||
@@ -16,6 +16,13 @@ def loadDataSet():
|
||||
|
||||
|
||||
def createC1(dataSet):
|
||||
"""createC1(创建一个数据集)
|
||||
|
||||
Args:
|
||||
dataSet 加载的原始数据集
|
||||
Returns:
|
||||
frozenset 返回一个元素为frozenset格式的list
|
||||
"""
|
||||
C1 = []
|
||||
for transaction in dataSet:
|
||||
for item in transaction:
|
||||
@@ -23,20 +30,23 @@ def createC1(dataSet):
|
||||
# 遍历所有的元素,然后append到C1中
|
||||
C1.append([item])
|
||||
# 对数组进行 从小到大 的排序
|
||||
print 'sort前=', C1
|
||||
C1.sort()
|
||||
# frozenset表示冻结的set集合,元素无可改变;可以把它当字典的key来使用
|
||||
# frozenset表示冻结的set集合,元素无改变;可以把它当字典的key来使用
|
||||
print 'sort后=', C1
|
||||
print 'frozenset=', map(frozenset, C1)
|
||||
return map(frozenset, C1)
|
||||
|
||||
|
||||
def scanD(D, Ck, minSupport):
|
||||
"""scanD
|
||||
"""scanD(计算支持support, retList表示满足support的key, supportData表示全集的集合)
|
||||
|
||||
Args:
|
||||
D 原始数据集, D用来判断,CK中的元素,是否存在于原数据D中
|
||||
Ck 合并后的数据集
|
||||
D 原始数据集, D用来判断,CK中的元素,是否存在于原数据D中
|
||||
Ck 合并后的数据集
|
||||
Returns:
|
||||
retList 支持度大于阈值的集合
|
||||
supportData 全量key的字典集合
|
||||
retList 支持度大于阈值的集合
|
||||
supportData 全量key的字典集合
|
||||
"""
|
||||
# ssCnt 临时存放Ck的元素集合,查看Ck每个元素 并 计算元素出现的次数 生成相应的字典
|
||||
ssCnt = {}
|
||||
@@ -68,8 +78,8 @@ def aprioriGen(Lk, k):
|
||||
"""aprioriGen(循环数据集,然后进行两两合并)
|
||||
|
||||
Args:
|
||||
Lk 频繁项集
|
||||
k 元素的前k-2相同,就进行合并
|
||||
Lk 频繁项集的list
|
||||
k 元素的前k-2相同,就进行合并
|
||||
Returns:
|
||||
retList 元素两两合并的数据集
|
||||
"""
|
||||
@@ -80,7 +90,8 @@ def aprioriGen(Lk, k):
|
||||
for j in range(i+1, lenLk):
|
||||
L1 = list(Lk[i])[: k-2]
|
||||
L2 = list(Lk[j])[: k-2]
|
||||
# print '-----', Lk, Lk[i], L1
|
||||
# print '-----i=', i, k-2, Lk, Lk[i], list(Lk[i])[: k-2]
|
||||
# print '-----j=', j, k-2, Lk, Lk[j], list(Lk[j])[: k-2]
|
||||
L1.sort()
|
||||
L2.sort()
|
||||
# 第一次L1,L2为空,元素直接进行合并,返回元素两两合并的数据集
|
||||
@@ -100,25 +111,30 @@ def apriori(dataSet, minSupport=0.5):
|
||||
minSupport 支持度的阈值
|
||||
Returns:
|
||||
L 频繁项集的全集
|
||||
supportData 所有元素的支持度全集
|
||||
supportData 所有元素和支持度的全集
|
||||
"""
|
||||
# 冻结每一行数据
|
||||
# C1表示让元素转化为frozenset,并按照顺序存放到list中
|
||||
C1 = createC1(dataSet)
|
||||
# 对每一行进行set转换,然后存放到集合中
|
||||
D = map(set, dataSet)
|
||||
|
||||
# 计算支持support, L1表示满足support的key, supportData表示全集的集合
|
||||
print 'D=', D
|
||||
# 计算支持support, 计算在数据集D中,C1集合中元素是否满足minSupport
|
||||
# L1表示满足support的key, supportData表示全集的集合
|
||||
L1, supportData = scanD(D, C1, minSupport)
|
||||
# print "L1=", L1, "\n", "outcome: ", supportData
|
||||
|
||||
# L加了一层list, L一共2曾list
|
||||
L = [L1]
|
||||
k = 2
|
||||
# 判断L的第一层list是否有元素,就说说:L1是否有元素
|
||||
while (len(L[k-2]) > 0):
|
||||
# 合并k-2相同的数据集
|
||||
# 如果L的每个元素子项和后面任意一个元素项,进行对比, 就对前后2个频繁项集的合并,得到CK
|
||||
print 'k=', k, L, L[k-2]
|
||||
Ck = aprioriGen(L[k-2], k)
|
||||
# print '-----------', D, Ck
|
||||
print 'Ck', Ck
|
||||
|
||||
# 计算合并后的数据集的支持度
|
||||
# Lk满足支持度的key的list, supK表示key全集
|
||||
# print 'Ck', Ck
|
||||
Lk, supK = scanD(D, Ck, minSupport)
|
||||
# 如果字典没有,就追加元素,如果有,就更新元素
|
||||
supportData.update(supK)
|
||||
@@ -132,7 +148,7 @@ def apriori(dataSet, minSupport=0.5):
|
||||
|
||||
|
||||
def calcConf(freqSet, H, supportData, brl, minConf=0.7):
|
||||
"""calcConf
|
||||
"""calcConf(对2元素的频繁项,计算置信度,例如: {1,2}/{1} 或者{1,2}/{2} 看是否满足条件)
|
||||
|
||||
Args:
|
||||
freqSet 每一组的各个元素
|
||||
@@ -147,9 +163,11 @@ def calcConf(freqSet, H, supportData, brl, minConf=0.7):
|
||||
prunedH = []
|
||||
for conseq in H:
|
||||
# 计算自信度的值,例如元素 H=set(1, 2), 分别求:supportData[1] 和 supportData[2]
|
||||
# 例如: confidence= frozenset([2, 3, 5]) frozenset([2, 3]) frozenset([5])
|
||||
# print 'confidence=', freqSet, conseq, freqSet-conseq
|
||||
conf = supportData[freqSet]/supportData[freqSet-conseq]
|
||||
if conf >= minConf:
|
||||
# 意思是说: 只要买了freqSet-conseq集合,一定会买 conseq集合【freqSet-conseq集合 和 conseq集合 是全集】
|
||||
print freqSet-conseq, '-->', conseq, 'conf:', conf
|
||||
brl.append((freqSet-conseq, conseq, conf))
|
||||
prunedH.append(conseq)
|
||||
@@ -168,17 +186,19 @@ def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
|
||||
Returns:
|
||||
prunedH 记录 可信度大于阈值的集合
|
||||
"""
|
||||
# 去除list列表中第一个出现的冻结的set集合
|
||||
# H[0]是freqSet的元素组合的第一个元素
|
||||
m = len(H[0])
|
||||
# 判断,freqSet的长度是否>组合的长度+1
|
||||
# 判断,freqSet的长度是否>组合的长度+1, 避免过度匹配 例如:计算过一边{1,2,3} 和 {1, 2} {1, 3},就没必要再计算了 {1,2,3}和{1,2,3}的组合关系
|
||||
if (len(freqSet) > (m + 1)):
|
||||
# 合并相邻的集合,组合为2/3/..n的集合
|
||||
print 'freqSet******************', len(freqSet), m + 1, freqSet, H, H[0]
|
||||
# 合并数据集集合,组合为2/3/..n的集合
|
||||
Hmp1 = aprioriGen(H, m+1)
|
||||
# 返回记录 可信度大于阈值的集合
|
||||
Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf)
|
||||
# 如果有2个结果都可以,直接返回结果就行,下面这个判断是多余,我个人觉得
|
||||
# print 'Hmp1=', Hmp1
|
||||
print 'Hmp1=', Hmp1
|
||||
if (len(Hmp1) > 1):
|
||||
# print '-------'
|
||||
print '----------------------', Hmp1
|
||||
# print len(freqSet), len(Hmp1[0]) + 1
|
||||
rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)
|
||||
|
||||
@@ -188,7 +208,7 @@ def generateRules(L, supportData, minConf=0.7):
|
||||
|
||||
Args:
|
||||
L 频繁项集的全集
|
||||
supportData 所有元素的支持度全集
|
||||
supportData 所有元素和支持度的全集
|
||||
minConf 可信度的阈值
|
||||
Returns:
|
||||
bigRuleList 关于 (A->B+置信度) 3个字段的组合
|
||||
@@ -274,25 +294,25 @@ def getTransList(actionIdList, billTitleList): #this will return a list of lists
|
||||
|
||||
|
||||
def main():
|
||||
# 以前的测试
|
||||
# # 以前的测试
|
||||
# project_dir = os.path.dirname(os.path.dirname(os.getcwd()))
|
||||
# 收集并准备数据
|
||||
# # 收集并准备数据
|
||||
# dataMat, labelMat = loadDataSet("%s/resources/Apriori_testdata.txt" % project_dir)
|
||||
|
||||
# 现在的的测试
|
||||
# # 1. 加载数据
|
||||
# dataSet = loadDataSet()
|
||||
# print(dataSet)
|
||||
# # 调用 apriori 做购物篮分析
|
||||
# # 支持度满足阈值的key集合L,和所有key的全集suppoerData
|
||||
# L, supportData = apriori(dataSet, minSupport=0.5)
|
||||
# # print L, supportData
|
||||
# print '\ngenerateRules\n'
|
||||
# rules = generateRules(L, supportData, minConf=0.05)
|
||||
# print rules
|
||||
# 1. 加载数据
|
||||
dataSet = loadDataSet()
|
||||
print(dataSet)
|
||||
# 调用 apriori 做购物篮分析
|
||||
# 支持度满足阈值的key集合L,和所有元素和支持度的全集suppoerData
|
||||
L, supportData = apriori(dataSet, minSupport=0.5)
|
||||
print L, '\n', supportData
|
||||
print '\ngenerateRules\n'
|
||||
rules = generateRules(L, supportData, minConf=0.25)
|
||||
print rules
|
||||
|
||||
# 项目实战
|
||||
# 构建美国国会投票记录的事务数据集
|
||||
# # 项目实战
|
||||
# # 构建美国国会投票记录的事务数据集
|
||||
# actionIdList, billTitleList = getActionIds()
|
||||
# # 测试前2个
|
||||
# # transDict, itemMeaning = getTransList(actionIdList[: 2], billTitleList[: 2])
|
||||
@@ -304,20 +324,20 @@ def main():
|
||||
# rules = generateRules(L, supportData, minConf=0.95)
|
||||
# print rules
|
||||
|
||||
# 项目实战
|
||||
# 发现毒蘑菇的相似特性
|
||||
# 得到全集的数据
|
||||
dataSet = [line.split() for line in open("testData/Apriori_mushroom.dat").readlines()]
|
||||
L, supportData = apriori(dataSet, minSupport=0.3)
|
||||
# 2表示毒蘑菇,1表示可食用的蘑菇
|
||||
# 找出关于2的频繁子项出来,就知道如果是毒蘑菇,那么出现频繁的也可能是毒蘑菇
|
||||
for item in L[1]:
|
||||
if item.intersection('2'):
|
||||
print item
|
||||
# # 项目实战
|
||||
# # 发现毒蘑菇的相似特性
|
||||
# # 得到全集的数据
|
||||
# dataSet = [line.split() for line in open("testData/Apriori_mushroom.dat").readlines()]
|
||||
# L, supportData = apriori(dataSet, minSupport=0.3)
|
||||
# # 2表示毒蘑菇,1表示可食用的蘑菇
|
||||
# # 找出关于2的频繁子项出来,就知道如果是毒蘑菇,那么出现频繁的也可能是毒蘑菇
|
||||
# for item in L[1]:
|
||||
# if item.intersection('2'):
|
||||
# print item
|
||||
|
||||
for item in L[2]:
|
||||
if item.intersection('2'):
|
||||
print item
|
||||
# for item in L[2]:
|
||||
# if item.intersection('2'):
|
||||
# print item
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user