前言:这是一个老故事, 但每次看总是能从中想到点什么.在一家超市里,有一个有趣的现象:尿布和啤酒赫然摆在一起出售。但是这个奇怪的举措却使尿布和啤酒的销量双双增加了。这不是一个笑话,而是发生在美国沃尔玛连锁店超市的真实案例,并一直为商家所津津乐道。原来,美国的妇女们经常会嘱咐她们的丈夫下班以后要为孩子买尿布。而丈夫在买完尿布之后又要顺手买回自己爱喝的啤酒,因此啤酒和尿布在一起购买的机会还是很多的。 是什么让沃尔玛发现了尿布和啤酒之间的关系呢?正是商家通过对超市一年多原始交易数字进行详细的分析,才发现了这对神奇的组合。 无独有偶。美国密执安州有一家名为"阿汉"的小餐馆有个异常奇特的做法:经常光顾该餐馆的顾客, 只要愿意,便可报上自己的常住地址,在客户登记簿上注册,开一个"户头",以后顾客每次到这里来就餐,餐馆都会如实地在其户头上记下用餐款额。每年的9月30日,餐馆便会按客户登记簿上的记载算出每位顾客从上年9月30日以来在餐馆的消费总额,然后再按餐馆纯利10%的比例算出每位顾客应得的利润分发给顾客,这样,餐馆自然就常常门庭若市。阿汉餐馆给顾客分红的方法虽然损失了一部分纯利,但却使顾客感到自己与餐馆的利润息息相关,自己也是餐馆的一员。这样一来,餐馆密切了与消费者的关系,吸引了许多回头客。 这种让食客成为"股东"的做法其实也是一种"组合"式的生意之道,不同的是前者是明显的"物质组合",而后者是隐蔽的"人员组合",两者都是以消费者心甘情愿地付出而给老板带来了滚滚利润,何乐而不为呢?

上面的例子我们不讨论他的经营之道,我们来挖掘其中用到的技术思想。

一:关联分析

我们一般去网点或者店里购物,一般都会有这样的购物清单吧。

Apriori算法的原理与python 实现。-LMLPHP

有的人说,这种有什么用?那再来看看这个:

Apriori算法的原理与python 实现。-LMLPHP

这是我随便找的一家网店的超值搭配。你会说这有什么联系吗?

假如,我是这个店长,我分析了我店里的历史数据,看见衣服1和裤子2被同一个顾客购买的可能性很大。那我是不是可以在我的店里搭配这两个套餐,同时也可以在给点击衣服1的人推荐我的裤子2,说不定,这个人看上了裤子2,又感觉与衣服1搭配还挺合适的,那么就会把这两件都买下来,商家在这次的购物行为中就赚了一笔。

那可能,你会问,小的数据集我可能很快就分析出来了,假如我的店很大,有很多物品。类似于天猫超市那样的,我怎样才能找到他们的关联项呢?不会让我穷尽所有操作吧。那么下面我们来介绍Apriori帮助店长解决这个繁琐的问题。

二 :Apriori算法

先介绍两个概念:

支持度:用于表示给定数据集的频繁程度。公式:Apriori算法的原理与python 实现。-LMLPHP 分子为X与Y同

时出现的概率,N为整个数据的个数。

置信度:Y在包含X的事物中出现的频繁程度。公式:Apriori算法的原理与python 实现。-LMLPHP

项集:一个购物篮中任意的商品组合就是一个项集(包括单独的一个,但是项集不能出现重复的商品)

频繁项集:出现的项集大于一个人为设置的阀值,我们称之为频繁项集。

三:算法过程

先通过偏离数据库得到一个项集(也就是一个商品),然后计算他的支持度,如果小于某一个阀值则删除,大于则保留,然后组合求2两个项的项集的支持度。低于阀值则去掉,高于阀值则保留。用上面的用以上步骤重复处理新得到的频繁项集合, 直到没有频繁项集合产生。其中候选项集产生的过程被分为连接与剪技两个部分。 采用这种方式, 使得所有的频繁项集既不会遗漏又不会重复。 为提高频繁项集逐层产生的效率, Apriori算法利用了两个重要的性质用于压缩搜索空间。

性质 1  k维数据项目集 X是频繁项目集的必要条件是它的所有 k-1维子集均是频繁项目集。

性质 2  若 k维项目集 X中有 (k-1)维子集不是频繁项集, 则 X不是频繁项集

四:算法的python实现

本算法和数据来自机器学习实战。

'''
Created on Mar 24, 2011
Ch 11 code
@author: Peter
'''
from numpy import *

def loadDataSet():

return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]

def createC1(dataSet):
C1 = []

for transaction in dataSet:

for item in transaction:

if not [item] in C1:
C1.append([item])


C1.sort()

return map(frozenset, C1)#use frozen set so we
#can use it as a key in a dict

def scanD(D, Ck, minSupport):
ssCnt = {}

for tid in D:

for can in Ck:

if can.issubset(tid):

if not ssCnt.has_key(can): ssCnt[can]=1

else: ssCnt[can] += 1

numItems = float(len(D))
retList = []
supportData = {}

for key in ssCnt:
support = ssCnt[key]/numItems

if support >= minSupport:
retList.insert(0,key)
supportData[key] = support

return retList, supportData

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

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)#scan DB to get Lk

supportData.update(supK)
L.append(Lk)
k += 1

return L, supportData

def generateRules(L, supportData, minConf=0.7): #supportData is a dict coming from scanD

bigRuleList = []

for i in range(1, len(L)):#only get the sets with two or more items

for freqSet in L[i]:
H1 = [frozenset([item]) for item in freqSet]

if (i > 1):
rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)

else:
calcConf(freqSet, H1, supportData, bigRuleList, minConf)

return bigRuleList

def calcConf(freqSet, H, supportData, brl, minConf=0.7):
prunedH = [] #create new list to return

for conseq in H:
conf = supportData[freqSet]/supportData[freqSet-conseq] #calc confidence

if conf >= minConf:

print freqSet-conseq,'-->',conseq,'conf:',conf
brl.append((freqSet-conseq, conseq, conf))
prunedH.append(conseq)

return prunedH

def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
m = len(H[0])

if (len(freqSet) > (m + 1)): #try further merging

Hmp1 = aprioriGen(H, m+1)#create Hm+1 new candidates

Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf)

if (len(Hmp1) > 1): #need at least two sets to merge

rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)


def pntRules(ruleList, itemMeaning):

for ruleTup in ruleList:

for item in ruleTup[0]:

print itemMeaning[item]

print " -------->"

for
item in ruleTup[1]:

print itemMeaning[item]

print "confidence: %f" % ruleTup[2]

print #print a blank line

因为Apriori算法比较简单,也没什么好说的,有时会要结合具体硬件进行改进,也可以通过数据的存储形式进行改变。

在这里说一下,那个阿汉餐馆为每个人开个账户我们是不是可以根据他的消费习惯,给他推荐一些相似的餐品。这就用到我们的推荐算法了,哈哈。

05-04 07:39