1. 程式人生 > 其它 >機器學習--Apriori演算法

機器學習--Apriori演算法

一、基本原理

關聯分析(association analysis)就是從大規模資料集中尋找物品間的隱含關係。這裡的主要問題是,尋找物品的不同組合是一項十分耗時的任務,所需計算代價很高,蠻力搜尋方法並不能解決這個問題,所以需要用更智慧的方法在合理的時間內找到頻繁項集。Apriori演算法正是基於該原理得到的。

關聯分析是一種在大規模資料集中尋找有趣關係的任務。這些關係分為兩種形式:頻繁項集和關聯規則。頻繁項集(frequent item sets)是經常出現在一起的物品的集合。其中頻繁的概念可以用支援度來定義。支援度(support)被定義為資料集中包含該項集的記錄所佔的比例,保留滿足最小支援度的項集。關聯規則(association rules)暗示兩種物品之間可能存在很強的關係。關聯的概念可用置信度或可信度來定義。

我們的目標是找到經常在一起購買的物品集合,通過使用集合的支援度來度量其出現的頻率。一個集合的支援度是指有多少比例的交易記錄包含該集合。假如有N種物品,那麼這些物品就有2^N-1種項集組合。即使只出售100種物品,它們之間的組合數對於現有的計算機也是吃不消的。為了降低這種複雜度,有人提出了Apriori演算法。Apriori原理是說如果某個項集是頻繁的,那麼它的所有子集也是頻繁的。反過來,如果某一項集是非頻繁集,那麼它的所有超集(包含該集的集合)也是非頻繁的。

二、演算法流程

對資料集的每條交易記錄transaction

對每個候選項集can:

檢查一下can是否是transaction的子集:

如果是,則增加can的計數值

對每個候選項集:

如果其支援度不低於最小值,則保留該項集

返回所有頻繁項集列表

三、演算法的特點

優點:易編碼實現

缺點:在大規模資料集上可能較慢。

適用資料範圍:數值型或標稱型。

四、python程式碼實現

1、建立簡單資料集

############################# #功能:建立一個簡單的測試資料集 #說明:數字1、2、3、4、5代表物品1、、、物品5, # 每個子集代表顧客的交易記錄 #輸入變數:空 #輸出變數:資料集 #############################

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

2、建立大小為1的不重複項集

################################## #功能:構建一個大小為1的不重複候選項集 #輸入變數:測試資料集 #輸出變數:候選項集合 #############################

def create_c1(data_set):

c1 = []

for transaction in data_set: # 遍歷資料集中所有的交易記錄 for item in transaction: # 遍歷每條記錄的每一項 if [item] not in c1: # 如果該物品沒有在c1中 c1.append([item]) c1.sort()

# set和frozenset皆為無序唯一值序列。 # set和frozenset最本質的區別是前者是可變的、後者是不可變的。 # frozenset的不變性,可以作為字典的鍵值使用。

return map(frozenset, c1)

3、保留滿足最小支援度的項集

#################################### #功能:掃描候選集集合,把支援度大於最小支援度的元素留下來, #通過去掉小於支援度的元素,可以減少後面查詢的工作量。 #輸入變數:資料集,候選項集列表,最小支援度 #data_set, ck, min_support #輸出變數:大於最小支援度的元素列表,包含支援度的字典 #ret_list, support_data ####################################


def scan_d(data_set, ck, min_support):
    D = map(set, data_set)
    ss_cnt = {}
    for tid in D:  # 遍歷資料集中所有交易
        for can in ck:  # 遍歷候選項集
            # 判斷候選集中該集合是資料集中交易記錄的子集
            # set().issubset()判斷是否是其子集
            if can.issubset(tid):
                # 判斷該集合是否在空字典ss_cnt
                if can not in ss_cnt.keys():
                    ss_cnt[can] = 1
                else:
                    ss_cnt[can] += 1
    num_items = float(len(D))
    ret_list = []  # 存放大於最小支援度的元素
    support_data = {}
    for key in ss_cnt:  # 遍歷字典中每個鍵值
        support = ss_cnt[key]/num_items  # 計算支援度
        if support >= min_support:
            ret_list.insert(0, key)
        support_data[key] = support
    return ret_list, support_data

4、生成候選項集

#################################### #功能:生成候選項集 ck #輸入變數:頻繁項集,項集元素個數 lk, k #輸出變數:每個子集個數為k的不重複集 ret_list

#################################### def apriori_gen(lk, k):

print 'lk=', lk print 'k=', k ret_list = [] len_lk = len(lk)

for i in xrange(len_lk-1): for j in xrange(i+1, len_lk): if len(lk[i] | lk[j]) == k: ret_list.append(lk[i] | lk[j]) # 各個子集進行組合 ret_list = set(ret_list) # 去除重複的組合,構建不重複的集合 return ret_list

5、組織完整的Apriori演算法

####################################

#虛擬碼如下:

#當集合中項的個數大於0時

# 構建一個k個項組成的候選項集的列表

# 檢查資料以確認每個項集都是頻繁的

# 保留頻繁項集並構建k+1項組成的候選項集的列表

#功能:構建頻繁項集列表 #輸入變數:原始資料集,最小支援度 data_set, min_support #輸出變數:頻繁項集列表,大於最小支援度的元素列表 #l, ret_list ####################################

def apriori(data_set, min_support=0.5):

c1 = create_c1(data_set)

# #掃描資料集,由C1得到L1 l1, support_data = scan_d(data_set, c1, min_support)

l = [l1] # 構建L列表,其中第一個元素為L1列表

k = 2 # 前面已經生成L1,所以這裡從2開始 while len(l[k-2]) > 0:

ck = apriori_gen(l[k-2], k) # 由L(k-1)生成Ck

print 'ck=', ck

# 掃描資料集,由Ck得到Lk lk, support_k = scan_d(data_set, ck, min_support) support_data.update(support_k) l.append(lk) k += 1

return l, support_data

6、關聯規則生成函式

#################################### #功能:生成一個包含可信度的規則列表 #輸入變數: # 頻繁項集列表 l # 包含那些頻繁項集支援資料的字典 support_data # 最小可信度閾值 min_conf #輸出變數:包含可信度的規則列表 big_rule_list #################################### def generate_rules(l, support_data, min_conf=0.7):

big_rule_list = [] for i in xrange(1, len(l)): for freq_set in l[i]: h1 = [frozenset([item]) for item in freq_set] print "h1=", h1

if i > 1: rules_from_conseq(freq_set, h1, support_data, big_rule_list, min_conf) else: calc_conf(freq_set, h1, support_data, big_rule_list, min_conf) return big_rule_list

7、計算規則可信度

#################################### #功能:計算規則的可信度 #輸入變數: # 頻繁項集 freq_set # 每個頻繁項集轉換成的列表 h # 包含那些頻繁項集支援資料的字典 support_data # 關聯規則 brl #輸出變數:包含可信度的規則列表 pruned_h #################################### def calc_conf(freq_set, h, support_data, brl, min_conf=0.7): pruned_h = [] for conseq in h: conf = support_data[freq_set]/support_data[freq_set-conseq] print 'freq_set:', freq_set print 'conseq:', conseq print 'freq_set-conseq:', freq_set-conseq if conf >= min_conf: print freq_set-conseq, '-->', conseq, 'conf:', conf brl.append((freq_set-conseq, conseq, conf)) pruned_h.append(conseq) return pruned_h

#################################### #功能:頻繁項集中元素多於兩個用這個函式生成關聯規則 #輸入變數: # 頻繁項集 freq_set # 每個頻繁項集轉換成的列表 h # 包含那些頻繁項集支援資料的字典 support_data # 關聯規則 brl #輸出變數:空 #################################### def rules_from_conseq(freq_set, h, support_data, brl, min_conf=0.7): m = len(h[0]) if len(freq_set) > (m+1): hmp1 = apriori_gen(h, m+1) hmp1 = calc_conf(freq_set, hmp1, support_data, brl, min_conf) if len(hmp1) > 1: rules_from_conseq(freq_set, hmp1, support_data, brl, min_conf)

程式碼測試:

def main():
    data_set = load_data_set()
    print 'data_set=', data_set
    c1 = create_c1(data_set)
    print 'c1=', c1
    # l1, support_data = scan_d(data_set, c1, 0.5)
    # print 'l1=', l1
    # print 'support_data=', support_data
    l, support_data = apriori(data_set)
    print 'l=', l
    print 'support_data=', support_data
    rules = generate_rules(l, support_data)
    print 'rules=', rules
if __name__ == '__main__':
    main()