機器學習演算法--關聯分析
1.主要概念
關聯分析:從大規模資料集中尋找物品間隱含關係
頻繁項集:經常出現在一起的物品的集合
關聯規則:兩種物品之間可能存在的關係
支援度:資料集中包含該項集的記錄所佔的比例
置信度(可信度): 對於規則A-->B 定義可信度=支援度(A,B)/支援度(A),即規則在A中的適應程度
2.Aprior原理
假設四種商品0,1,2,3,則所有可能的項集如下所示:
N中物品,項集可能數有2的N次冪-1,若計算每一種可能項集的支援度,計算量太大。
Aprior原理:某個項集是頻繁的,所有子集也是頻繁的;若某個項集非頻繁,他的所有超集也是非頻繁的。
若23非頻繁,則023,123,0123必定也非頻繁,因此不需要計算其支援度,這樣可以大大減少求解的數量。
3.Aprior演算法發現頻繁集
載入資料集:
def loadDataSet():
return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
根據資料集建立單元素項集C1:
def createC1(dataSet): C1 = [] #資料集的每一項 for transaction in dataSet: #每一項的單個元素 for item in transaction: if not [item] in C1: C1.append([item]) #進行排序 C1.sort() #返回一個排序的單元素集合 frozenset表示集合不能被修改 return list(map(frozenset, C1))#use frozen set so we #can use it as a key in a dict
分解資料集的每一個單元素,放入一個集合中
由C1過濾掉不符合最小支援度的單元素,得到L1
def scanD(D, Ck, minSupport): #key 項 value次數 ssCnt = {} #遍歷資料集 for tid in D: #遍歷頻繁項集 for can in Ck: #某一項是資料的子集 if can.issubset(tid): #python3語法改變 if not can in ssCnt: ssCnt[can]=1 else: ssCnt[can] += 1 #總資料數 numItems = float(len(D)) #非頻繁項 retList = [] #key 項 value 支援度 supportData = {} for key in ssCnt: #支援度 support = ssCnt[key]/numItems if support >= minSupport: #記錄非頻繁項 retList.insert(0,key) supportData[key] = support return retList, supportData
返回為單元素的非頻繁項集,以及單元素頻繁項集的支援度。
由Lk得到Ck,由Lk兩兩合併,得到不重複的Ck 0,1,2 (0,1) (0,2 ) (1,2)
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個元素,如果相同則進行合併。如果相同,前k-2個元素相同,合併之後新項集變為k長度。
由資料集產生一定支援度的頻繁項集:
def apriori(dataSet, minSupport = 0.5):
C1 = createC1(dataSet)
D = list(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
資料集--C1---L1---...Ck----Lk 返回最終的頻繁項集。
4.頻繁項集挖掘關聯規則
關聯規則可信度的定義 規則P--->H可信度: support(P|H)/support(P)
根據頻繁項集先生成一個可能的關聯規則集合,然後逐一測試可信度,把不滿足可信度的規則去掉
當某一條規則不滿足可信度時,那麼所有子集也都不滿足可信度要求。
由頻繁項集以及頻繁項集的項與支援度來產生關聯規則
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
例如頻繁項集L:
[[frozenset({5}), frozenset({2}), frozenset({3}), frozenset({1})], [frozenset({2, 3}), frozenset({3, 5}), frozenset({2, 5}), frozenset({1, 3})], [frozenset({2, 3, 5})], []]
對應的支援度:
{frozenset({1}): 0.5, frozenset({3}): 0.75, frozenset({4}): 0.25, frozenset({2}): 0.75, frozenset({5}): 0.75, frozenset({1, 3}): 0.5, frozenset({2, 5}): 0.75, frozenset({3, 5}): 0.5, frozenset({2, 3}): 0.5, frozenset({1, 5}): 0.25, frozenset({1, 2}): 0.25, frozenset({2, 3, 5}): 0.5}
初始i=1 首先計算長度為1的項集的可信度,直接計算即可,可信度大於0.7 記錄下來輸出。
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
一條規則對應左邊--右邊 ,H對應右邊項
freqSet頻繁項集 H可以出現在元素右側的元素列表
計算H的長度,如果頻繁項集長度大於len(H)+1,說明H應該繼續合併以產生長度更長的集合,計算新集合與頻繁項集的可信度,如果新集合中長度大於1,則繼續合併。
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)
觀察了另一位大神的程式碼,思路清晰多了:
https://blog.csdn.net/hanghangaidoudou/article/details/79306220
規則形式 左邊---右邊
左邊由頻繁項集產生 右邊首先是長度為1的可能選項,然後通過合併長度來產生更長的長度。例如:
{1} {2} {3} {1,2} {1,3} {123} {1234}
當頻繁項的長度l==1時,此時是無法推匯出關聯規則
l==2時 以{1,2} 可能的規則 12---1 12---2 分別檢查每一種的可信度 右邊元素記錄在H
l>2時,123 首先測試 123-1 123-2 123-3 然後測試123--12 123-13 123-23
1234 1234-1 1234-2 1234-3 1234-4 1234-12 1234-13 1234-14 1234-23 1234-24 1234-34 1234-123 1234-134 1234-234
def getBigRule(freq,support,minConf=0.5):
'''
input:
freq : the frequent k-itemset,k=1,2,...n
support: corresponding support
outpur:
bigRuleList: a list of all the rule that satisfy min confidence
'''
bigRuleList=[]
m=len(freq)
for i in range(1,m):
genRules(freq[i],support,bigRuleList,minConf)
return bigRuleList
def genRules(freq,support,brl,minConf=0.5):
'''
extract rules that satisfy min confidence from a list of k-itemset(k>1)
put the eligible rules in the brl
'''
#如果頻繁項集為空,則直接返回
if len(freq)==0:return
#如果頻繁項集每一項長度2 1,2 則規則是1,2---1 1,2---2
if len(freq[0])==2: #handle 2-itemset
for itemset in freq:
for conseq in itemset:
conseq=frozenset([conseq])
#集合做差
conf=support[itemset]/support[itemset-conseq]
if conf>=minConf:
print (itemset-conseq, '-->',conseq,'conf:',conf)
brl.append((itemset-conseq,conseq,conf))
elif len(freq[0])>2:
H=[]
# 1,2,3 ---1 2 3
for itemset in freq:
# first generate 1-consequence list
#123--1 123--2 123--3
for conseq in itemset:
conseq=frozenset([conseq])
conf=support[itemset]/support[itemset-conseq]
if conf>=minConf:
print (itemset-conseq, '-->',conseq,'conf:',conf)
brl.append((itemset-conseq,conseq,conf))
H.append(conseq)
m=2
# generate 2,...,k-1 consequence
# 123--12 123--13 123--23
while m<len(freq[0]):
H=generateLk(H,m)
for conseq in H:
conf=support[itemset]/support[itemset-conseq]
if conf>=minConf:
print (itemset-conseq, '-->',conseq,'conf:',conf)
brl.append((itemset-conseq,conseq,conf))
m+=1
def generateLk(freq,k):
'''
input:
freq: the itemset in freq is k-1 itemset
k: create k-itemset from k-1_itemset
output:
Lk:a list of k-itemset,frequent and infrequent
'''
Lk=[]
for i in range(0,len(freq)-1):
for j in range(i+1,len(freq)):
if list(freq[i])[0:k-2]==list(freq[j])[0:k-2]:#fore k-1 item is identity
Lk.append(frozenset(freq[i]|freq[j]))
return Lk