1. 程式人生 > >Apriori演算法進行關聯分析(2)

Apriori演算法進行關聯分析(2)

頻繁項集及關聯規則的應用中,購物、搜尋引擎中的查詢詞等,下面看一個美國國會議員投票的例子。

1. 示例:發現國會投票中的模式

這個例子雖然在資料的獲取過程中有點複雜,但我覺得還是很有必要分析下整個過程。

1. 收集資料:構建美國國會投票記錄的事務資料集

我們希望最終資料的格式:即每一行代表美國國會的一個成員,而每列都是他們投票的物件。

(1)需要提前做的準備:

  • 安裝python-votesmart
  • 獲得API key(這需要申請自己的key)

    (2)使用相關的API

  • bills=votesmart.votes.getBillsByStateRecent()獲得最近的100條議案

  • bill.title:獲得議案標題 bill.billId:獲得議案ID號

  • bill=votesmart.votes.getBill(11820)通過getBill()方法獲得每條議案的更多內容,此時的bill是一個BillDetail物件,包含大量的完整資訊。

  • bill.actions:檢視議案的所有行為,包括議案被提出時的行為,以及議案在投票時的行為

  • action.stageaction.actionID:我們所感興趣的是投票時的行為,所以得到行為的狀態和其相應的ID。

  • voteList=votesmart.votes.getBillActionVotes(),通過getBillActionVotes()
    方法獲得某條議案的具體投票資訊。其中voteList是一個包含vote物件的列表。

(2)為了將billID轉化為actionID,並對actionID進行過濾只保留包含投票資料的actionID,這樣得到剩下的議案都是有趣的議案:

# -*- coding: utf-8 -*-
"""
Created on Thu Nov 09 20:52:41 2017
"""

from time import sleep
from votesmart import votesmart  # 此模組需要單獨下載

votesmart.apikey = 'a7fa40adec6f4a77178799fae4441030'
# 這裡需要改換成自己的API key # 收集美國國會議案中action ID的函式 def getActionIds(): actionIdList = []; billTitleList = [] fr = open('recent20bills.txt') for line in fr.readlines(): billNum = int(line.split('\t')[0]) # 得到了議案的ID try: billDetail = votesmart.votes.getBill(billNum) # 得到一個billDetail物件 for action in billDetail.actions: # 遍歷議案中的所有行為 if action.level == 'House' and \ (action.stage == 'Passage' or action.stage == 'Amendment Vote'): actionId = int(action.actionId) print 'bill: %d has actionId: %d' % (billNum, actionId) actionIdList.append(actionId) billTitleList.append(line.strip().split('\t')[1]) except: # API呼叫時發生錯誤 print "problem getting bill %d" % billNum sleep(1) # 禮貌訪問網站而做出些延遲,避免過度訪問 return actionIdList, billTitleList

此時得到了有actionID的議案,接下來可以獲取這些actionID的投票資訊。

(3)選舉人可以投是或否的表決票,也可以棄權,需要將上述資訊轉化為類似於項集或者交易資料庫之類的東西,而一條交易記錄只包含一個項的出現或者不出現,並不包含項出現的次數。

在使用Apriori之前需要構建事務資料庫:首先建立一個字典,字典中使用政客的名字作為鍵值,然後對投票進行編碼,其對每條議案使用兩個條目:bill+’Yea’以及bill+’Nay’。

投票資訊到元素項的轉換結果:
這裡寫圖片描述

下面的函式就是以actionID串作為輸入並利用votesmart的API來抓取投票記錄的函式,然後將每個選舉人的投票轉化為一個項集,每個選舉人對應於一行或者說事物資料庫中的一條記錄。

# 基於投票資料的事物列表填充函式 
def getTransList(actionIdList, billTitleList): 
    itemMeaning = ['Republican', 'Democratic'] # 建立一個含義列表
    for billTitle in billTitleList: # 遍歷所有的議案
        itemMeaning.append('%s -- Nay' % billTitle) # 在議案標題後面新增Nay(反對)
        itemMeaning.append('%s -- Yea' % billTitle) # 在議案標題後新增Yea(同意)
    transDict = {} # 用於加入元素項
    voteCount = 2
    for actionId in actionIdList: # 遍歷getActionIds()返回的每一個actionId
        sleep(3) # 延遲訪問,防止過於頻繁的API呼叫 
        print 'getting votes for actionId: %d' % actionId
        try:
            voteList = votesmart.votes.getBillActionVotes(actionId) # 獲得某個特定的actionId的所有投票資訊
            for vote in voteList: # 遍歷投票資訊
                if not transDict.has_key(vote.candidateName):  # 如果沒有該政客的名字
                    transDict[vote.candidateName] = [] # 用該政客的名字作為鍵來填充transDict
                    if vote.officeParties == 'Democratic':  # 獲取該政客的政黨資訊
                        transDict[vote.candidateName].append(1)
                    elif vote.officeParties == 'Republican':
                        transDict[vote.candidateName].append(0)
                if vote.action == 'Nay':
                    transDict[vote.candidateName].append(voteCount)
                elif vote.action == 'Yea':
                    transDict[vote.candidateName].append(voteCount + 1)
        except: 
            print "problem getting actionId: %d" % actionId
        voteCount += 2
    return transDict, itemMeaning  # 返回事物字典和元素項含義列表

測試演算法,基於投票挖掘關聯規則

dataSet=[transDict[key] for key in transDict.keys() ]
L,suppData=apriori(dataSet,0.5) # 得到頻繁項集
rules=generateRules(L,suppData,0.99)

結果得到:
這裡寫圖片描述

最後可以基於關聯規則和支援度進行分析,解決實際問題。

2. 示例:發現毒蘑菇的相似特徵

有時我們並不想尋找所有頻繁項集,而只對包含某個特定元素項的項集感興趣。在本章這個最後的例子中,我們會尋找毒蘑菇中的一些公共特徵,利用這些特徵就能避免吃到那些有毒的蘑菇。UCI的機器學習資料集合中有一個關於肋形蘑菇的23種特徵的資料集,每一個特徵都包含一個標稱資料值。我們必須將這些標稱值轉化為一個集合,這一點與前面投票例子中的做法類似。幸運的是,已經有人已經做好了這種轉換。Roberto Bayardo對UCI蘑菇資料集進行了解析,將每個蘑燕樣本轉換成一個特徵集合。其中,枚舉了每個特徵的所有可能值,如果某個樣本包含特徵,那麼該特徵對應的整數值被包含資料集中。

此時可以利用Apriori演算法尋找包含特徵值為2(這裡‘2’代表了有毒的特徵)的頻繁項集。

程式碼:

# 主函式
mushDataSet=[line.split() for line in open ('mushroom.dat').readlines()] 
L,suppData=apriori(mushDataSet,minSupport = 0.5)
print 'L[1]:',L[1]
for item in L[1]: # 在單元素頻繁項集中找到包含特徵2的頻繁集
    if item.intersection('2'):
        print 'item:',item

這裡只給出了呼叫語句,具體的Apriori演算法參考:Apriori演算法發現頻繁集
只需改動主函式語句即可:

執行結果:

L[1]: [frozenset(['59', '85']), frozenset(['63', '85']), frozenset(['86', '34']), frozenset(['76', '86']), frozenset(['59', '34']), frozenset(['24', '85']), frozenset(['39', '85']), frozenset(['39', '86']), frozenset(['86', '59']), frozenset(['86', '53']), frozenset(['2', '85']), frozenset(['86', '36']), frozenset(['24', '90']), frozenset(['39', '36']), frozenset(['53', '85']), frozenset(['63', '86']), frozenset(['86', '85']), frozenset(['24', '34']), frozenset(['36', '34']), frozenset(['90', '85']), frozenset(['39', '34']), frozenset(['67', '34']), frozenset(['90', '63']), frozenset(['76', '34']), frozenset(['76', '85']), frozenset(['86', '67']), frozenset(['53', '34']), frozenset(['90', '86']), frozenset(['90', '36']), frozenset(['59', '36']), frozenset(['90', '53']), frozenset(['63', '36']), frozenset(['90', '59']), frozenset(['24', '86']), frozenset(['90', '39']), frozenset(['36', '85']), frozenset(['85', '34']), frozenset(['63', '34']), frozenset(['85', '67']), frozenset(['90', '34']), frozenset(['63', '59'])]
item: frozenset(['2', '85'])

由於這裡的支援度閾值較高,並且採用的是較小的項集來檢視特徵‘2’,所以得到的項集只有一個。

通過觀察這些特徵,以便知道了解野蘑菇的那些方面。如果看到其中任何一個特徵,那麼這些蘑菇就不要吃了。也即是說關聯分析就是通過一個目標特徵來分析得到和其相關聯的其他特徵,進而可以對其採取措施。