apriori推薦算法
大數據時代開始流行推薦算法,所以作者寫了一篇教程來介紹apriori推薦算法。
推薦算法大致分爲:
- 基於物品和用戶本身
- 基於關聯規則
- 基於模型的推薦
基於物品和用戶本身
基於物品和用戶本身的,這種推薦引擎將每個用戶和每個物品都當作獨立的實體,預測每個用戶對於每個物品的喜好程度,這些信息往往是用一個二維矩陣描述的。由於用戶感興趣的物品遠遠小於總物品的數目,這樣的模型導致大量的數據空置,即我們得到的二維矩陣往往是一個很大的稀疏矩陣。同時爲了減小計算量,我們可以對物品和用戶進行聚類, 然後記錄和計算一類用戶對一類物品的喜好程度,但這樣的模型又會在推薦的準確性上有損失。
基於關聯規則
基於關聯規則的推薦(Rule-based Recommendation):關聯規則的挖掘已經是數據挖掘中的一個經典的問題,主要是挖掘一些數據的依賴關係,典型的場景就是“購物籃問題”,通過關聯規則的挖掘,我們可以找到哪些物品經常被同時購買,或者用戶購買了一些物品後通常會購買哪些其他的物品,當我們挖掘出這些關聯規則之後,我們可以基於這些規則給用戶進行推薦。
基於模型的推薦
基於模型的推薦(Model-based Recommendation):這是一個典型的機器學習的問題,可以將已有的用戶喜好信息作爲訓練樣本,訓練出一個預測用戶喜好的模型,這樣以後用戶在進入系統,可以基於此模型計算推薦。這種方法的問題在於如何將用戶實時或者近期的喜好信息反饋給訓練好的模型,從而提高推薦的準確度。
其實在現在的推薦系統中,很少有隻使用了一個推薦策略的推薦引擎,一般都是在不同的場景下使用不同的推薦策略從而達到最好的推薦效果,例如 Amazon 的推薦,它將基於用戶本身歷史購買數據的推薦,和基於用戶當前瀏覽的物品的推薦,以及基於大衆喜好的當下比較流行的物品都在不同的區域推薦給用戶,讓用戶可以從全方位的推薦中找到自己真正感興趣的物品。探索推薦引擎內部的祕密,第 1 部分: 推薦引擎初探
Apriori算法 是一種最有影響力的 挖掘布爾關聯規則 的頻繁項集的算法,這個算法是屬於上面第二條基於關聯規則
推薦的算法,本文着重講解該算法的計算。
按照網上最簡單的例子來進行分析:
支持度support=P(AB),指的是事件A和事件B同時發生的概率。
置信度confidence=P(B|A)=P(AB)/P(A),指的是發生事件A的基礎上發生事件B的概率。
大致步驟爲:
掃描
->計數
->剪枝
->頻繁集
->強規則
掃描
掃描候選項集,並將所有的種類彙總,上圖可知有種類["A","B","C","D","E"]
計數
計數即統計種類的個數,上圖可知:{'A':
2, 'C': 3, 'D': 1, 'E': 3, 'B': 3}
剪枝
剪枝就是把不滿足支持度的部分給去掉,支持度自己設定,上圖第一次剪枝去掉了D,那麼數據庫中的所有D也要被去掉,即下次計算不被包含
頻繁集
第一次剪枝後就得到了第一個頻繁集L1,L1還能繼續壓縮,所以繼續重複前面的幾個步驟,直到無法再壓縮
前面這些步驟用python寫了代碼如下:
# !/usr/bin/python3.4
# -*- coding: utf-8 -*-
# 獲取所有元素種類
def getkinds(array):
arr = []
for item in array:
for value in item:
if value in arr:
pass
else:
if value != "+":
arr.append(value)
return arr
# 候選集長度
def getcount(array, support):
# 第一次掃描
# C1
dict = {}
for item in array:
for key in item:
if key in dict.keys():
dict[key] += 1
else:
dict[key] = 1
# 第一次剪枝
newdict = judge_spport(dict, support)
# 第二次掃描
# 構造項集C2
# 兩兩組合
arr = []
kinds = getkinds(newdict.keys())
for m in range(0, len(kinds)):
for n in range(m + 1, len(kinds)):
arr.append(kinds[m] + "+" + kinds[n])
# 計數
dict = {}
for item in array:
for values in arr:
value = values.split("+")
if value[0] in item and value[1] in item:
if values in dict:
dict[values] += 1
else:
dict[values] = 1
# print(dict)
# {'B+A': 1, 'A+E': 1, 'C+E': 2, 'B+E': 3, 'C+B': 2, 'C+A': 2}
# 第二次剪枝
newdict = judge_spport(dict, support)
# print(newdict)
# {'C+E': 2, 'B+E': 3, 'C+B': 2, 'C+A': 2}
# 第三次掃描
# 構造項集C2
# 兩兩組合
arr = []
kinds = getkinds(newdict.keys())
for m in range(0, len(kinds)):
for n in range(m + 1, len(kinds)):
for k in range(n + 1, len(kinds)):
arr.append(kinds[m] + "+" + kinds[n] + "+" + kinds[k])
# 計數
dict = {}
for item in array:
for values in arr:
value = values.split("+")
if value[0] in item and value[1] in item and value[2] in item:
if values in dict:
dict[values] += 1
else:
dict[values] = 1
# print(dict)
# {'E+B+A': 1, 'E+C+A': 1, 'E+B+C': 2, 'B+C+A': 1}
# 第三次剪枝
newdict = judge_spport(dict, support)
# {'B+E+C': 2}
return newdict
# 剪枝
# 刪除不符合支持度的key
def judge_spport(dict, support):
dic = dict.copy()
for key in dict.keys():
if dict[key] < support:
del dic[key]
return dic
if __name__ == '__main__':
support = 2
info = [["A", "C", "D"], ["B", "C", "E"], ["A", "B", "C", "E"], ["B", "E"]]
dict = getcount(info, support)
print(dict)
打印結果爲:
{'C+B+E': 2}
強規則計算
上文可知頻繁集{C,B,E}的非空真子集有{B,C},{B,E},{C,E},{B},{C}和{E},對應置信度如下:
B&&C->E confidence=2/2=100%
B&&E->C confidence=2/3=66%
C&&E->B confidence=2/2=100%
B ->C&&E confidence=2/3=66%
C ->B&&E confidence=2/3=66%
E ->B&&C confidence=2/3=66%
對於規則" If B and E then C",同時購買B和E的人中,有66.67%會購買C。
即置信度confidence=P(B|A)=P(AB)/P(A)
計算強規則的代碼爲:
# 計算強規則
def getconfidence(dict,array):
# 一一組合
kinds = getkinds(dict.keys())
arr = kinds
newdict = {}
for i in range(0,len(arr)):
denominator1 = 0
numerator1 = 0
denominator2 = 0
numerator2 = 0
for item in array:
if arr[i] in item:
denominator1 += 1
temp = getkinds(dict.keys())
temp.remove(arr[i])
if temp[0] in item and temp[1] in item:
numerator1 += 1
key1 = arr[i] + "->" + temp[0] + "+" + temp[1]
for item in array:
temp = getkinds(dict.keys())
temp.remove(arr[i])
if temp[0] in item and temp[1] in item:
numerator2 += 1
if arr[i] in item:
denominator2 += 1
key2 = temp[0] + "+" + temp[1] + "->" + arr[i]
if denominator1 == 0:
newdict[key1] = str(numerator1) + "denominator1"
else:
newdict[key1] = str(numerator1) + "/" + str(denominator1)
if numerator2 == 0:
newdict[key2] = str(denominator2) + "numerator2"
else:
newdict[key2] = str(denominator2) + "/" + str(numerator2)
return newdict
打印結果爲:
{'B->E+C': '2/3', 'B+C->E': '2/2', 'E+C->B': '2/2', 'E->B+C': '2/3', 'C->B+E': '2/3', 'B+E->C': '2/3'}
結果解說
可以知道購買B和C的人很可能買E,買了E和C的人很可能買B,而其他的概率可能要小一些,例如購買了B的人,很可能買E和C。