使用Apriori算法進行關聯分析--代碼學習

#-*- coding: utf-8 -*-
def loadDataSet():
    return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]

#構建集合C1,C1是大小爲1的所有候選項集的集合
def createC1(dataSet):
    C1 = [] #創建一個空列表,用來存儲所有不重複的項值
    #遍歷數據集中的所有交易記錄,transaction依次爲數據集中的每條交易記錄,即每個項集,
    # 如依次爲[1,3,4],[2,3,5],[1,2,3,5],[2,5]
    for transaction in dataSet:
        for item in transaction: #遍歷記錄中的每一個項,item是每條交易記錄中的物品,如項集[1,3,4]中的1,3,4
            if not [item] in C1:#如果某個物品項沒有在C1中出現,則將其添加到C1中
                #不是簡單地添加每個物品項,而是添加只包含該物品項的一個列表,
                # 目的是爲每個物品構建一個集合,因爲後面要進行集合操作
                C1.append([item])
    C1.sort() #對大列表進行排序
    #將列表中的每個單元素列表映射到frozenset(),最後返回frozenset的列表
    #frozenset是指被冰凍的集合,就是它們是不可改變的,這裏必須使用frozenset而不是set類型,因爲之後
    #必須要將這些集合作爲字典鍵值使用,使用frozenset可以實現,而set卻做不到
    return map(frozenset, C1)

#數據集Ck,包含候選集合的列表D,感興趣項集的最小支持度minSupport
def scanD(D,Ck,minSupport):
    ssCnt = {}
    for tid in D:#遍歷數據集中的所有交易記錄
        for can in Ck: #遍歷C1中的所有候選集
            if can.issubset(tid): #如果C1中的集合是記錄的一部分,那麼增加字典中對應的計數值
                if not ssCnt.has_key(can):  ssCnt[can] = 1
                else: ssCnt[can] += 1
    numItems = float(len(D)) #numItems是數據集中交易記錄的條數
    retList = []
    supportData = {}
    for key in ssCnt:
        support = ssCnt[key] / numItems #計算支持度
        if support >= minSupport:
            retList.insert(0,key) #retList列表中包含了滿足最小支持度要求的集合,insert(0,key)表示在列表的首部插入新的集合
        supportData[key] = support #以字典的形式將滿足最小支持度要求的集合和其支持度存儲在supportData
    return retList, supportData


#*********************** Apriori算法 **********************


# 輸入參數爲頻繁項集列表Lk,k位輸出的合成的項集的元素個數,
# 如當k = 2時,輸出爲CK [frozenset([1, 3]), frozenset([1, 2]), frozenset([1, 5]), frozenset([2, 3]), frozenset([3, 5]), frozenset([2, 5])]
# 輸出中,每個項集都是兩個元素
def aprioriGen(Lk,k):
    retList = [] #創建一個空列表
    lenLk = len(Lk) #計算Lk中的元素數目
    for i in range(lenLk):
        for j in range(i+1, lenLk):
            #從這步開始,就是取列表Lk中每個集合的前面k-2個元素進行比較,
            # 如果相等,就將這兩個集合合爲一個大小爲k的集合
            L1 = list(Lk[i])[:k-2]; L2 = list(Lk[j])[:k-2]
            L1.sort(); L2.sort()
            if L1 == L2:
                retList.append(Lk[i] | Lk[j])
    return retList

#輸入爲數據集,以及支持度,函數會生成候選項集的列表
def apriori(dataSet, minSupport = 0.5):
    C1 = createC1(dataSet) # 創建C1
    D = map(set, dataSet) # 讀入數據集並將其轉化爲D(集合列表)
    L1,supportData = scanD(D,C1,minSupport) # 利用scanD創建L1,
    L = [L1] # 將L1放入列表L中,L會包含L1,L2, L3 ....通過下面的while循環依次放入,直到下一個大的項集爲空
    k = 2
    while(len(L[k-2]) > 0): # 代表直到下一個大的項集爲空時,停止循環
        CK = aprioriGen(L[k-2], k) # 首先使用aprioriGen來創建Ck
        # 使用scanD基於Ck來創建Lk,Ck是一個候選項集列表,然後scanD會遍歷Ck,丟掉不滿足最小支持度要求的項集
        LK, supK = scanD(D, CK, minSupport)
        supportData.update(supK)
        L.append(LK) # Lk列表被添加到L中
        k += 1 # 同時增加k的值
    return L, supportData

#主函數
# 輸入參數爲頻繁項集列表,包含那些頻繁項集支持數據的字典,最小可信度閾值
# 函數輸出爲一個包含可信度的規則列表
def generateRules(L, supportData, minConf = 0.7):
    bigRuleList = []
    # 因爲無法從單元素項集中構建關聯規則,所以要從包含兩個或更多元素的項集開始構建
    for i in range(1, len(L)):  #只可獲取有兩個或更多元素的集合,所以i從1開始
        for freqSet in L[i]:# 遍歷L中的每一個頻繁項集,並對每個頻繁項集創建只包含單個元素集合的列表H1
            H1 = [frozenset([item]) for item in freqSet]
            if (i > 1):
                rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf) # 如果i > 1,頻繁項集的元素數目超過2,則進一步合併
            else:
                calcConf( freqSet, H1, supportData, bigRuleList, minConf) # 當i=1時,頻繁項集的元素數目爲2,此時直接進行計算可信度
    return bigRuleList

# 計算規則的可信度以找到滿足最小可信度要求的規則
def calcConf(freqSet, H, supportData, brl, minConf = 0.7):
    prunedH = [] #創建一個空列表,用來保存符合最小可信度要求的規則列表
    for conseq in H: #遍歷H中的所有項集
        # 根據可信度的計算式:一條規則P--> H的可信度定義爲support(P | H) / support(P)
        # 所有一個項集 conseq的可信度計算如下:
        conf = supportData[freqSet] / supportData[freqSet - conseq]  # 計算可信度
        if conf >= minConf:
            print freqSet-conseq, '-->',conseq,'conf:',conf # 如果滿足最小可信度,則將規則輸出到屏幕顯示
            brl.append((freqSet - conseq, conseq, conf)) # 將通過檢查的規則保存在brl中,即是bigRuleList
            prunedH.append(conseq) # 保存符合最小可信度要求的規則列表,並返回
    return prunedH

# 輸入參數,freqSet是頻繁項集,H是可以出現在規則右部的元素列表
def rulesFromConseq(freqSet, H, supportData, brl, minConf = 0.7):
    m = len(H[0]) # 計算H中的頻繁集大小爲m
    if (len(freqSet) > (m+1)): #看該頻繁項集是否大到可以移除大小爲m的子集
        Hmp1 = aprioriGen(H, m+1) # 生成H中元素的無重複組合,結果存儲在Hmp1中,這也是下一次迭代的H列表,Hmp1中包含所有的規則
        Hmp1 = calcConf( freqSet, Hmp1, supportData, brl, minConf) # 測試Hmp1中的規則的可信度以確定規則是否滿足要求,返回一個符合最小可信度要求的規則列表
        if (len(Hmp1) > 1): #如果不止一天規則滿足,那麼使用Hmp1迭代調用函數rulesFromConseq
            rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)

dataSet = loadDataSet()
L, supportData = apriori(dataSet, 0.5)
rules = generateRules(L, supportData, minConf = 0.5)
print rules

發佈了33 篇原創文章 · 獲贊 41 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章