1. 程式人生 > >機器學習演算法--關聯分析

機器學習演算法--關聯分析

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