1. 程式人生 > >【機器學習】第4部分 關聯分析

【機器學習】第4部分 關聯分析

# -*- coding:utf-8 -*-

import itertools
import copy

'''
定義全域性變數k,即支援度計數k,此k也可以在執行程式之前輸入,簡單改動即可
'''
k = 2

'''
儲存頻繁項集的列表
'''
frequenceItem = []

'''
從txt檔案dataset.txt裡獲取事務集
'''


def getDataSet(args):
    f = open(args, 'r')
    source = f.readlines()
    f.close()
    dataset = []
    for line in source:
        temp1 = line.strip('\r\n')
        temp2 = temp1.split(',')
        dataset.append(temp2)
    return dataset


'''
初步掃描事務集,從事務集裡獲取候選1項集
方法的基本思路是:
定義一個集合tmp,將事務集的第一項作為tmp的初始集合
然後掃描事務集,將不在tmp裡的資料項加入tmp中
'''


def find_item(dataset):
    length = len(dataset)
    for i in range(0, length):
        if i == 0:
            tmp = set(dataset[i])
        tmp.update(set(dataset[i]))
    candidate = list(tmp)
    candidate.sort()
    return candidate


'''
從候選項集裡找出頻繁項集,其中num代表頻繁num+1項集
如num為0的為從候選1項集裡找出頻繁1項集
方法基本思路:
1、定義一個支援度列表count
2、對於每一個候選項,依次掃描事務集,如果該項出現在事務集中就將該項對應的count+1、定義一個支援度列表count+1
3、將每一項的count和k(支援度計數)進行比較,將count小於k的項剔除
'''

'''
其實不管num為0還是別的值演算法應該是一樣的,但是由於程式實現上的問題
num為0的時候選項集是一維列表,其它的時候,候選項集是二維列表,
畢竟只是自己寫著玩的,python還不熟,牽一髮而動全身,懶得改了
'''


def find_frequent(candidate, dataset, num):
    frequence = []
    length = len(candidate)
    count = []
    for i in range(0, length):
        count.append(0)
        count[i] = 0
        if num == 0:
            child = set([candidate[i]])
        else:
            child = set(candidate[i])
        for j in dataset:
            parent = set(j)
            if child.issubset(parent):
                count[i] = count[i] + 1
    for m in range(0, length):
        if count[m] >= k:
            frequence.append(candidate[m])
    return frequence


'''
先驗定理,剪枝掉不必要的候選n項集
方法思路:
1、依次取出候選項集裡的項
2、取出n項集裡的n-1項子集
3、如果所有的n-1項集不都都是頻繁n-1項集的子集,則刪除該候選項集
'''


def pre_test(candidate, num, frequence):
    r_candidate = copy.deepcopy(candidate)
    for each in candidate:
        for each2 in itertools.combinations(each, num):
            tmp = (list(each2))
            tag = 0
            for j in frequence:
                if num == 1:
                    if (tmp[0] == j):
                        tag = 1
                        break
                else:
                    if tmp == j:
                        tag = 1
                        break
            if tag == 0:
                r_candidate.remove(each)
                break
    return r_candidate


'''
通過頻繁n-1項集產生候選n項集,並通過先驗定理對候選n項集進行剪枝
方法思路:
1、如果是頻繁1項集,則通過笛卡爾積產生頻繁2項集
2、如果不是頻繁一項集,採用F(k-1) * F(k-1)方法通過頻繁n-1項集產生候選n項集
注:F(k-1) * F(k-1)方法在我的另一篇關聯演算法部落格上做了理論上的簡單介紹,或者也可以直接參看《資料探勘導論》
'''


def get_candidata(frequence, num):
    length = len(frequence)
    candidate = []
    if num == 1:
        for each in itertools.combinations(frequence, 2):
            tmp = list(each)
            tmp3 = []
            tmp3.append(tmp[0])
            tmp3.append(tmp[1])
            candidate.append(tmp3)
    else:
        for i in range(0, length - 1):
            tmp1 = copy.deepcopy(frequence[i])
            tmp1.pop(num - 1)
            for j in range(i + 1, length):
                tmp2 = copy.deepcopy(frequence[j])
                tmp2.pop(num - 1)
                if tmp1 == tmp2:
                    tmp3 = copy.deepcopy(frequence[i])
                    tmp3.append(frequence[j][num - 1])
                    candidate.append(tmp3)
    candidate2 = pre_test(candidate, num, frequence)
    return candidate2


'''
main程式
'''
if __name__ == '__main__':
    dataset = getDataSet('dataset.txt')
    Item = find_item(dataset)
    num = 0
    frequenceItem = []

'''
通過事務集找到頻繁項集,直至頻繁n項集為空,則退出迴圈
'''
while 1:
    if num == 0:
        candidate = Item
    else:
        candidate = get_candidata(frequenceItem[num - 1], num)
    frequenceItem.append(find_frequent(candidate, dataset, num))
    if frequenceItem[num] == []:
        frequenceItem.pop(num)
        break
    num = num + 1
'''
打印出頻繁項集
'''
for each in frequenceItem:
    print each