序列模式

什麼是序列模式

這裏寫圖片描述


Apriori處理的數據沒有考慮每個客戶在超市多次購物的情況。
序列模式:一個用戶在不同時間點的交易記錄就構成了一個購買序列,
N個用戶的購買序列就組成一個規模爲N的序列數據集.。

Apriori目的:挖掘出頻繁集,找到其中的關聯規則
對於Apriori處理的數據集設置支持度閾值爲:2
則(麪包機、麪包)爲頻繁集
設置可信度爲:0.7
則關聯規則:麪包機 這裏寫圖片描述 麪包
這條關聯規則的意義:在一次交易中買了麪包機,就很可能買麪包

序列模式目的:挖掘滿足最小支持度的頻繁序列
對於序列模式處理的數據集設置支持度閾值爲:2
則<麪包機 麪包> 爲頻繁序列
這條頻繁序列的意義:如果一個顧客買了麪包機,那麼他以後就回來買麪包

如果我來經營一家超市,通過Apriori算法,我需要將麪包機與麪包放在一起,通過序列模式,我知道如果一段時間內麪包機賣了很多,我將多進貨麪包

序列模式三個算法GSP SPADE PrifixSpan

GSP


GSP算法由Srikant&Agrawal於1996年提出

這裏寫圖片描述

這裏寫圖片描述

舉例:
數據集

設置支持度閾值爲:3
這裏寫圖片描述

(1)掃描序列數據庫,對每一項進行支持度統計,得到長度爲1的頻繁序列模式

支持度統計
這裏寫圖片描述

(2)根據長度爲1的頻繁序列,通過連接操作生成長度爲2的候選序列模式,然後掃描序列數據庫,計算每個候選序列的支持度,通過刪除操作產生長度爲2的頻繁序列模式

這裏寫圖片描述

這裏寫圖片描述

(3)根據長度爲2的頻繁序列,通過連接操作生成長度爲3的候選序列模式,然後掃描序列數據庫,計算每個候選序列的支持度,通過刪除操作產生長度爲3的頻繁序列模式

這裏寫圖片描述

這裏沒有統計<A,AB>,因爲<A,A>是非頻繁序列(根據公理:如果一個序列是頻繁序列,那麼它的子序列也是頻繁序列;如果一個序列是非頻繁序列,那麼包含它的序列也是非頻繁序列
沒有統計<B,AB>也是同樣的道理。

這裏寫圖片描述

SPADE


SPADE算法是Zaki在2001年發表的《An efficient algorithm for mining frequent sequences》提出的。

這裏寫圖片描述

這裏寫圖片描述

SPADE的算法過程和GSP類似,只是在掃描的時候不是掃描整個數據庫,而是掃描ID_LIST.

舉例:

這裏寫圖片描述

設置支持度閾值爲:3

1序列的ID_list

這裏寫圖片描述

紅色框代表非頻繁序列

2序列的ID_list

這裏寫圖片描述

注意:<A,A> 是由1頻繁序列A的ID_list生成的;<A,B> 是由1頻繁序列A的ID_list和1頻繁序列B的ID_list生成的;<(A,B)> 也是由1頻繁序列A的ID_list和1頻繁序列B的ID_list生成的

3序列的ID_list

這裏寫圖片描述

注意:<A,(AB)> 沒有生成ID_list,因爲<A,A> 是非頻繁的; <B,(AB)> 沒有生成ID_list,因爲 <B,A> 是非頻繁的;

SPADE:通過便利一次數據庫得到的經驗知識來降低多次對數據庫的掃描。
SPADE不僅通過減少對數據庫的掃描降低I/O成本通過搜索ID_list降低計算成本。

PrefixSpan

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

舉例:

這裏寫圖片描述

設置支持度閾值爲:3

(1)對數據庫中所有的項進行支持度統計,將支持度低於閾值的項從數據庫中刪除,得到長度爲1的前綴

這裏寫圖片描述

(2)對於每個長度爲1滿足支持度要求的前綴進行遞歸挖掘:

這裏寫圖片描述

注意:
B和_B不一樣,前者是前綴A與B在不同的項集,後者是和前綴A在相同的項集中。

a,b,c 分別對應PrefixSpan算法步驟第二步中的a,b,c

(3)重複第二步

這裏寫圖片描述

這裏寫圖片描述

GSP實驗


數據集採用的是Zaki在2001年發表的《An efficient algorithm for mining frequent sequences》中的一個例子。

這裏寫圖片描述

#coding=utf-8
import itertools
import sys
import datetime

#-----------------
class GSP(object):
    def __init__(self):
        self.queue = []

#----------------------------------------------------------#
#                     計算freq1                            #
#----------------------------------------------------------#
    def freq1(self, data, frequent_num):
        appear = ''
        freq1 = []
        appear_ele = []
        appear_ele2 = []
        for i in range(len(data)):
            appear = ''
            for j in range(len(data[i])):
                appear += data[i][j]
            appear_ele += list(set(appear))
        # print(appear_ele)
        appear_ele2 = list(set(appear_ele))
        # print(appear_ele2)
        for item in appear_ele2:
            itmes = appear_ele.count(item)
            if itmes >= frequent_num:
                freq1.append(item)
        print('頻繁1項集爲:%s' %freq1)
        return freq1

#----------------------------------------------------------#
#                     計算freq_more                        #
#----------------------------------------------------------#
    def freq_more(self, data, freq1):
        queue = []#所有的備選序列放在這裏面
        queue_new = []#最終結果在這裏面
        top = 0 #這個是queue_new的隊尾標號
        times = 3
        while True:

            if (queue_new == []): #爲空則代表這是第一次遍歷,python中的&&是and,||是or
                for i in range(len(freq1)):
                    for j in range(i+1, len(freq1)):
                        item = freq1[i] + freq1[j]
                        queue.append(item)
                for i in range(len(freq1)):
                    for j in range(len(freq1)):
                        if j != i:
                            item = freq1[i] +'->'+ freq1[j]
                            queue.append(item)#第一次遍歷後全部可能出現的情況
                for i in range(len(queue)):
                    freq_item = self.isFreq(queue[i], data)
                    if freq_item != 0:
                        queue_new.append(freq_item)
                queue = []#清空queue(備選序列)

            if (queue_new != []): #後幾次遍歷時要把所有的情況寫入空的queue中
                if top == len(queue_new) - 1: #表示沒有新加入元素,那麼終止 while 循環
                    print('頻繁多項集爲:%s' %queue_new)
                    break
                else:
                    demo_list = []#專門放'AB','BF','AF'這樣的頻繁序列,後面將他們合成爲更多成員的備選頻繁序列
                    for i in range(top, len(queue_new)):
                        if '->' not in queue_new[i]:
                            demo_list.append(queue_new[i])
                    demo_string = self.List_to_String(demo_list) #將列表中的元素拼接成字符串,諸如拼成'ABBFAF'
                    demo_ele = "".join(set(demo_string)) #刪除串中的重複元素,輸出'ABF'
                    if len(demo_ele) >= times:
                        if len(demo_ele) == times :#那麼demo_ele是唯一的備選成員
                            queue.append(demo_ele)
                            times += 1
                        else: #否則對備選字母進行排列組合,比如'ABCDE',一共能排列出10鍾情況,並把它們推入queue(待判斷成員隊列)
                            combin = self.Combinations(demo_ele, times)
                            for i in range(len(combin)):
                                queue.append(combin[i])
                            times += 1
                    ###-----####至此已經把備選頻繁尋列推入 queue ####-----###

                    queue = self.Make_time_queue(top, freq1, queue, queue_new)

                    ###-----#### 至此已經把 queue 放滿了備選成員 ####-----###

                    top = len(queue_new)# 更新隊尾指針 top 的位置

                    ###-----#### 檢測 queue 中的備選序列是否頻繁 ####-----###
                    for i in range(len(queue)):
                        freq_item = self.isFreq(queue[i], data) #---->> isFreq
                        if freq_item != 0: #如果這個成員是頻繁的
                            queue_new.append(freq_item)
                    queue = []

    #將列表中的字母合併成字符串
    def List_to_String(self, list):
        demo_string = ''

        for i in range(len(list)):
            demo_string = demo_string + list[i]
        return demo_string

    #demo_ele是待排列的字符串, times是將它們排列成幾個元素
    def Combinations(self, item, times):
        demo_list = []
        combin = []
        element = ''

        for i in range(1, len(item) +1):
            iter = itertools.combinations(item, i)
            demo_list.append(list(iter))
        demo_combin = demo_list[times -1]
        for i in range(len(demo_combin)):
            for j in range(len(demo_combin[0])):
                element += demo_combin[i][j]
            combin.append(element)
            element = ''
        return combin

    #判斷item是不是頻繁的
    def isFreq(self, item, data):
        num = 0

        if '->' not in item:   #類似如'ABF'
            for i in range(len(data)):
                for j in range(len(data[i])):
                    if self.isIn_Item(item, data, i, j) != 0:
                        num += 1
            if num >= 2:
                return item
            else:
                return 0
        else:                  #類似如‘D->B->A’
            item0 = item.split('->')

            for i in range(len(data)):
                array = 0
                j = 0
                while True:
                    if array == len(item0) or j == len(data[i]):
                        break
                    if len(item0[array]) >= 2: #如果類似 'BA' 形式
                        if self.isIn_Item(item0[array], data, i, j) == 1:
                            array += 1
                            j += 1
                        else:
                            j += 1
                    else:
                        if item0[array] in data[i][j]:
                            array += 1
                            j += 1
                        else:
                            j += 1
                if array == len(item0):
                    num += 1
            if num >= 2:
                return item
            else:
                return 0

    #判斷 item 是否在 data[i][j]中
    def isIn_Item(self, item, data, i, j):
        demo_num = 0

        for k in range(len(item)):
            if item[k] in data[i][j]:
                demo_num += 1
        if demo_num == len(item):
            return 1
        else:
            return 0

    #
    def isIn_Time(self, item0, data, i, j):
        num = 0

        item0_lenth = len(item0)
        if item0_lenth == 2:
            for m in range(j+1, len(data[i])):
                if item0[1] in data[i][m]:
                    num += 1
        else:
            if item0[item0_lenth -2] in data[i][j]:
                for m in range(j+1, len(data[i])):
                    if item0[item0_lenth -1] in data[i][m]:
                        num += 1
                        break
        return num

    #創造新的備選時間序列
    def Make_time_queue(self, top, freq1, queue, queue_new):
        for i in range(top, len(queue_new)):
#           for j in range(len(freq1)):
            if '->' not in queue_new[i]:
                difference = self.Difference(queue_new[i], freq1)
                for j in range(len(difference)):
                    queue.append(difference[j] + '->' +queue_new[i]) #諸如 'D->AB'
                    queue.append(queue_new[i] + '->' +difference[j]) #諸如 'AB->D'
            else:
                difference = self.Difference(queue_new[i], freq1)
                for j in range(len(difference)):
                    queue.append(queue_new[i] + '->' + difference[j]) #諸如'B->A' 擴展成 'B->A->D'
        return queue

    #尋找兩個字符串中的不同字母,並提取出來
    def Difference(self, item, freq1):
        demo_list = []

        if '->' not in item:
            for i in range(len(freq1)):
                if freq1[i] not in item:
                    demo_list.append(freq1[i])
        else:
            demo_item = item.split('->') #將諸如'A->B'拆分成 'A','B'
            demo_item_string = self.List_to_String(demo_item) #合併成'AB'
            for i in range(len(freq1)):
                if freq1[i] not in demo_item_string:
                    demo_list.append(freq1[i])
        return demo_list


#                          main                           #
#----------------------------------------------------------#
data = {0:['CD','ABC','ABF','ACDF'],
        1:['ABF','E'],
        2:['ABF'],
        3:['DGH','BF','AGH']}


starttime = datetime.datetime.now()
g= GSP()
freq1 = g.freq1(data,2)
g.freq_more(data, freq1)
endtime = datetime.datetime.now()

print(endtime - starttime)

實驗截圖
這裏寫圖片描述

問題:
序列模式挖掘出頻繁序列假設爲 <A,B> ,這表明A發生後隔一段時間可能發生B,但隔一段時間到底是隔多長時間呢?

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