1. 程式人生 > >Apriori演算法關聯規則學習

Apriori演算法關聯規則學習

關聯分析是在大規模資料中發現有趣關係的演算法。這種關係包括:

1)頻繁項集:經常出現在一起的物品組合。

2)關聯規則:暗示兩種物品之間存在很強的關係。

1. 頻繁項集

怎麼定義一個組合是不是頻繁,有多頻繁?

交易號碼 商品
0 豆奶 萵苣
1 萵苣 尿布 葡萄酒 甜菜
2 豆奶 尿布 葡萄酒 橙汁
3 萵苣 豆奶 尿布 葡萄酒
4 萵苣 豆奶 尿布 橙汁

1.1 支援度 - support

資料集中包含該組合的記錄的頻率。例如支援度(豆奶) = 0.8;支援度(豆奶,尿布)= 0.6,因此可以定義一個最小支援度來排除一些非頻繁項集。

1.2 置信度 - confidence

置信度定義某條關聯規則的可信程度。比如從豆奶到尿布的一條關聯規則,置信度(豆奶 -> 尿布)= 支援度(豆奶,尿布)/ 支援度(豆奶)= 0.75。即若某條規則適用於豆奶,則其75%適用於(豆奶,尿布)組合。

2. Apriori演算法

尋找頻繁項集的最簡單方法是暴力搜尋,但是這個計算量是隨物品種類呈階乘增長的。因此使用更加智慧的Apriori演算法來過濾集合尋找頻繁項集。Apriori演算法的核心:頻繁項集的子集仍是頻繁項集,非頻繁項集的超集都是非頻繁項集

3. 頻繁項集生成

頻繁項集的度量標準:最小支援度。

# -*- coding: utf-8 -*-
""" 關聯規則學習, Apriori演算法 """

def load_data():
    return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]


class Apriori:
    """ apriori
    1. 計算單元素集合:
        [{1}, {2}, {3}, {4}, {5}]
    2. 剃掉不滿足最小支援度的元素: 
        [{1}, {2}, {3}, {5}]
    3. 計算二元素集合: 
        [{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5}, {3, 4}, {3, 5}, {4, 5}]
    4. 剃掉不滿足最小支援度的元素: 
        [(1, 3), (2, 3), (3, 5), (2, 5)]
    5. ....重複上述步驟, 知道集合元素包含所有單元素[{1, 2, 3, 5}]
    6. 獲取最終的頻繁集:
        [[{1}, {2}, {3}, {4}, {5}],
         [(1, 3), (2, 3), (3, 5), (2, 5)],
         [(2, 3, 5)]]
    """
    def __init__(self, minSupport):
        #  最小支援度
        self.minSupport = minSupport
    
    def _single_ele_set(self, train_x):
        """ 建立單元素集合列表 
        train_x:        全部訓練資料, 如[[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
        single_ele_set: 單元素集合, 如[{1}, {3}, {4}, {2}, {5}]
        """
        single_ele_set = []
        length = len(train_x)
        for i in range(length):
            for j in range(len(train_x[i])):
                if set([train_x[i][j]]) not in single_ele_set:
                    single_ele_set.append(set([train_x[i][j]]))
        return single_ele_set
    
    def _cal_support(self, train_x, k_ele_set):
        """ 計算支援度 
        train_x:    全部訓練資料, 如[[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
        k_ele_set:  如[{1}, {3}, {4}, {2}, {5}]
        """
        recordCnt = len(train_x)
        train_x = map(set, train_x)
        support = {}
        
        # k_ele_set中, 每個元素集在train_x中出現的次數
        for record in map(set, train_x):
            for j in k_ele_set:
                if j.issubset(record):
                    if tuple(j) not in support.keys():
                        support[tuple(set(j))] = 1
                    else:
                        support[tuple(set(j))] += 1
        
        # 求每個元素集的支援度
        for i in support.keys():
            support[i] = support[i] / recordCnt
        
        # 剔除不滿足最小支援度的元素集
        temp = support.copy()
        for i in temp.keys():
            if temp[i] < self.minSupport:
                support.pop(i)
        
        # 求出頻繁項集
        support = list(support.keys())
        return support
        
    def _k_ele_set(self, freqSet_k, k):
        """ 根據k-1元素集合建立k元素集合列表 
        fregSet_k:  k-1元素集合, 如[{1}, {3}, {2}, {5}]
        k_ele_set:  單元素集合, 如[{1, 3}, {1, 2}, {1, 5}, {2, 3}, {3, 5}, {2, 5}]
        """
        k_ele_set = []
        for i in range(len(freqSet_k)):
            for j in range(i+1, len(freqSet_k)):
                k_ele_set.append(set(freqSet_k[i]) | set(freqSet_k[j]))
                
        # 列表去重
        temp = k_ele_set.copy()
        k_ele_set = []
        for i in range(len(temp)):
            if temp[i] not in k_ele_set:
                k_ele_set.append(temp[i])
        return k_ele_set
    
    def apriori(self, train_x):
        """ apriori """
        single_ele_set = self._single_ele_set(train_x)
        print("1元素集合列表為: ")
        print(single_ele_set)
        
        freqSet_1 = [self._cal_support(train_x, single_ele_set)]
        print("1個元素的頻繁集為: ")
        print(freqSet_1, "\n")
            
        k = 2
        while len(freqSet_1[k-2]) > 0:
            k_ele_set = self._k_ele_set(freqSet_1[k-2], k)
            print("{0}元素集合列表為: ".format(k))
            print(k_ele_set)
            
            freqSet_k = self._cal_support(train_x, k_ele_set)
            print("{0}個元素的頻繁集為: ".format(k))
            print(freqSet_k, "\n")
            
            freqSet_1.append(freqSet_k)
            k += 1
        return freqSet_1
            

if __name__ == "__main__":
    train_x = load_data()
    
    obj = Apriori(minSupport=0.5)
    freqSet = obj.apriori(train_x)

4. 關聯規則生成

如圖{0, 1, 2, 3}頻繁集內能生成的所有關聯規則,其中深色表示置信度低,淺色表示置信度高。可以發現(0,1,2 -> 3)及其下面所有葉子節點全部置信度低。即如果某個頻繁項集的某條規則不滿足最小置信度,那麼他的子規則也不滿足最小置信度。


以頻繁集{萵苣,豆奶,尿布}為例,假設現在的關聯規則為(萵苣,豆奶 -> 尿布):

confidence(萵苣,豆奶 -> 尿布) = support(萵苣,豆奶,尿布) / support(萵苣,豆奶);

其子集為:

confidence(萵苣 -> 豆奶, 尿布) = support(萵苣,豆奶,尿布

) / support(萵苣);

顯然support(萵苣,豆奶) < support(萵苣);即confidence(萵苣,豆奶 -> 尿布) > confidence(萵苣 -> 豆奶, 尿布).

即若某個頻繁項集的關聯規則不滿足最小置信度,那麼這條關聯規則的子規則也不滿足最小置信度。通過這個規則,我們可以過濾集合,減少計算量。