機器學習 (十五) 關聯分析之Apriori算法

前言

       目前隨着數據量迅速增多,從海量數據中尋找有價值的信息帶來的成本也在不斷增加,傳統的搜索數據方式已經不能滿足我們的需要,我們先來通過一個算法看一下算法時間複雜度快慢帶來的影響,通過計算耗時我們會有個感性的認識,冒泡排序與快速排序想必大家都知道,複雜度分別爲n方和n*logn,複雜度隨着規模n變大時間如下;

n方 n*lgn n規模 時間
100 10 10 10倍
10000 200 100 500倍
1000000 3000 1000 1000倍 (省略)
1000000000000 6000000 1000000 100000倍

       上圖中有的值是約等於只爲對比效果,大家可以清晰的看出來隨着規模n增長,兩個算法所用時間對比,隨着數據量變大所面臨的挑戰越大,當數據規模到10的10次方時,耗時會差很多,如果快速排序執行30秒,那麼冒泡要運行5天以上,無疑中間增加耗費了很多臺服務器成本速度增加電費也急劇上升,可見好的數據挖掘算法至關重要,下面我們來一起看Apriori算法如何高效運行。

原理

基本概念

       apriori 英 [‘eɪprɑɪ’ɔ:rɪ] 先驗知識、演繹推演,言外之意是挖掘數據中的已有的信息、先驗知識信息,該詞在貝葉斯BA裏面代表先驗概率,最初的先驗經驗判斷。
        下面是一個數據集矩陣,可以理解爲數據庫裏面的記錄,每條記錄裏面有不同的數值。

tid
1 [[1,3,4]
2 [2,3,5]
3 [1,2,3,5]
4 [2,5]]
  • itemset 項集
    包含0個或者多個項的集合稱爲項集,如上面的第一條記錄[1,3,4] ,可以有六個項集,如[1,3]、[1]、[1,4]、[3,4]等。

  • support 支持度
    即某個項集出現的次數即支持度,有的書籍也說是次數除以總記錄數,如[2]出現了3次即支持度爲3,支持度可以作爲過濾條件過濾項集。

  • frequery itemset 頻繁項集
    滿足最小支持度的項集叫頻繁項集,如[1]出現了2次、[2]出現了3次,假如最小支持度爲3,那麼[2]是頻繁集,[1]不是頻繁集。

  • confident 可信度或置信度
    它是兩個頻繁集的商,如A、B兩個頻繁集,關聯規則爲A–>B ,那麼這條關聯規則的置信度爲support(AUB) / support(A)

  • association analysis 關聯分析
    關聯分析是一個過程即從數據集中發現哪個項集與哪個項集有關係的分析過程。

    Apriori思想

           思想:如果一個項集是頻繁項集,那麼它的所有子集也是頻繁項集,反過來說如果一個集合不是頻繁項集,那麼它的所有超集都不是頻繁的,根據這一條思想可以過濾掉很多項,減小了大量計算,想在想想這一思想似乎也很好理解,這有點像古代的連坐懲罰制度,只要組人中有一個人被觸發了,會連帶它的家族,包含這個人的家族都會受到牽連,株連九族的意思。
           實現思路:令k爲頻繁項集的層數,爲了不丟掉任何一個頻繁集,從k=1開始 逐層+1 ,第k層的候選集是由k-1層的頻繁集而來,然後由k層的候選集生成頻繁集,依次類推直到不能夠生成頻繁集爲止。

實戰

代碼

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import numpy as np

def loadDataSet():
    '''
    獲取數據集
    :return: 數據集
    '''
    return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]


def createC1(dataSet):
    '''
    生成候選項集 k=1時
    :param dataSet:
    :return:
    '''
    C1 = []
    # 循環每條記錄或事務
    for transaction in dataSet:
        # 循環每條記錄中的每項
        for item in transaction:
            if  not [item] in C1:
                C1.append([item])

    C1.sort()
    # 返回frozenset類型 ,用來做鍵值
    return map(frozenset,C1)


def scanD(D,Ck,minSupport):
    '''

    :param D:
    :param Ck:
    :param minSupport:
    :return:符合條件的項集和項集支持度
    '''
    # 統計候選元素出現的次數
    ssCnt = {}
    for tid in D:
        for can in Ck:
            if can.issubset(tid):
                if  not ssCnt.has_key(can):
                    ssCnt[can] = 1
                else:
                    ssCnt[can] += 1

    # 構建過濾集和支持集
    numItems = float(len(D))
    retList = []
    supportData = {}
    for key in ssCnt:
        support = ssCnt[key]/numItems
        if support >= minSupport:
            retList.insert(0,key)
        supportData[key] = support

    return retList,supportData

def aprioriGen(Lk ,k):
    '''
    生成頻繁集合
    :param Lk:
    :param k:
    :return:
    '''
    retList = []
    lenLk = len(Lk)
    for i in range(lenLk):
        for j in range(i+1,lenLk):
            print "i== %s" % i
            print "j== %s" % j

            print "Lk[i]== %s" % Lk[i]
            print "list(Lk[i])== %s" % list(Lk[i])

            print "Lk[j]== %s" % Lk[j]
            print "list(Lk[j])== %s" % list(Lk[j])

            L1 = list(Lk[i])[:k-2]
            L2 = list(Lk[j])[:k-2]
            print "L1== %s" % L1
            print "L2== %s" % L2

            L1.sort()
            L2.sort()
            if L1 == L2:
                retList.append(Lk[i] | Lk[j] )
    return retList






def apriori(dataSet,minSupport = 0.5):
    '''
    求頻繁項集以及對應的支持度
    :param dataSet:
    :param minSupport:
    :return:
    '''
    # 創建候選集合
    C1 = createC1(dataSet)
    print "C1 = %s" % C1
    D = map(set,dataSet)
    print "D = %s" % D
    L1,supportData = scanD(D,C1,minSupport)
    print "L1 = %s" % L1
    print "supportData = %s" % supportData
    L = [L1]
    k = 2
    while (len(L[k-2]) > 0):
        Ck = aprioriGen(L[k-2],k)
        Lk ,supK = scanD(D,Ck,minSupport)
        supportData.update(supK)
        L.append(Lk)
        k += 1
    return L,supportData

if  __name__ == '__main__':
    dataSet = loadDataSet()
    L,s = apriori(dataSet)

    print L
    print s

問題

  • 效率問題
    該算法每次都需要頻繁訪問數據集或者數據庫,無疑給DB帶來了很大壓力,是否有辦法優化呢?FP-growth只需要兩次訪問數據集,有興趣的可以查查資料
  • 數據挖掘和數據分析關係
    主要在如下散點方面區分
    計算機編程能力的要求
    在對行業的理解的能力
    專業知識面的要求

總之一句話來概括的話,數據分析師更關注於業務層面,數據挖掘工程師更關注於

總結

        該算法是數據挖掘領域重要算法,對於認識和學習挖掘方面都有益處,後面將繼續學習其他算法。

題外思考

從鏈黴素、DDT、海洛因的發明思考?
       鏈黴素是美國瓦克斯曼教授發明了,從鏈黴菌培養液中提取的抗生素,因此命名爲鏈黴素,它的發現治癒了困擾人類上千年的結核病,具有重大意義,從瓦克斯曼發明鏈黴素的過程來看是曲折、堅信、幸運等各種因素所致。
       瓦克斯曼開始在莫克公司支持在帶領團隊研製藥品,可惜由於多次的失敗莫克公司中途放棄,但瓦克斯曼認爲值的去做一直堅持下去繼續研究,在孤身一人時突然他的學生沙茨回到身邊同老師一起研究,造化弄人,沙茨剛加入不久就發現了鏈黴素,然後就是一段因爲誰發明鏈黴素的恩怨情仇…………

       阿司匹林、海洛因由美國化學教授霍夫曼所發明,現在想想同一個人發明了兩種影響極端的藥品,一種譽爲極品,一種譽爲魔鬼,均對後世產生了深遠影響,這種結論是經歷了長時間的驗證纔有了這樣的認識,剛開始發明出來時由於各種原因人們並沒有發現,海洛因剛問世時含量很低 不容易上癮,隨着含量在人體內累計,最終被人們發現了副作用。
       說道阿司匹林讓我想到了一首經常背誦的詩詞
                                   《送元二使安西》
                            渭城朝雨浥輕塵,客舍青青柳色新。
                            勸君更盡一杯酒,西出陽關無故人。
       柳樹千百年來一直存在,組成阿司匹林的水楊酸也一直有,其實我們需要的是發現的眼睛和質疑的思考。
       發明新藥或做事情一樣,不能有副作用把事情辦不好可以但不可以搞砸了,另外在世界上還有很多真理本來存在的事物等着我們去發現,你看不到並不代表沒有,像阿司匹林一樣它在那裏不管你看見還不不見,記得有幾句詞這樣寫的:

你見,或者不見我
我就在那裏
不悲不喜
你念,或者不念我
情就在那裏
不來不去

參考資料

1.https://blog.csdn.net/rongyongfeikai2/article/details/40457827
2.https://blog.csdn.net/kevinelstri/article/details/53487186
3.https://www.cnblogs.com/qwertWZ/p/4510857.html
2.http://baijiahao.baidu.com/s?id=1566792535800841&wfr=spider&for=pc

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章