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(萵苣);即confidence(萵苣,豆奶 -> 尿布) > confidence(萵苣 -> 豆奶, 尿布).
即若某個頻繁項集的關聯規則不滿足最小置信度,那麼這條關聯規則的子規則也不滿足最小置信度。通過這個規則,我們可以過濾集合,減少計算量。