FP-tree推薦算法

推薦算法大體分爲:html

  1. 基於物品和用戶自己
  2. 基於關聯規則
  3. 基於模型的推薦

基於物品和用戶自己

基於物品和用戶自己的,這種推薦引擎將每一個用戶和每一個物品都看成獨立的實體,預測每一個用戶對於每一個物品的喜愛程度,這些信息每每是用一個二維矩陣描述的。因爲用戶感興趣的物品遠遠小於總物品的數目,這樣的模型致使大量的數據空置,即咱們獲得的二維矩陣每每是一個很大的稀疏矩陣。同時爲了減少計算量,咱們能夠對物品和用戶進行聚類, 而後記錄和計算一類用戶對一類物品的喜愛程度,但這樣的模型又會在推薦的準確性上有損失。

基於關聯規則

基於關聯規則的推薦(Rule-based Recommendation):關聯規則的挖掘已是數據挖掘中的一個經典的問題,主要是挖掘一些數據的依賴關係,典型的場景就是「購物籃問題」,經過關聯規則的挖掘,咱們能夠找到哪些物品常常被同時購買,或者用戶購買了一些物品後一般會購買哪些其餘的物品,當咱們挖掘出這些關聯規則以後,咱們能夠基於這些規則給用戶進行推薦。

基於模型的推薦

基於模型的推薦(Model-based Recommendation):這是一個典型的機器學習的問題,能夠將已有的用戶喜愛信息做爲訓練樣本,訓練出一個預測用戶喜愛的模型,這樣之後用戶在進入系統,能夠基於此模型計算推薦。這種方法的問題在於如何將用戶實時或者近期的喜愛信息反饋給訓練好的模型,從而提升推薦的準確度。

其實在如今的推薦系統中,不多有隻使用了一個推薦策略的推薦引擎,通常都是在不一樣的場景下使用不一樣的推薦策略從而達到最好的推薦效果,例如 Amazon 的推薦,它將基於用戶自己歷史購買數據的推薦,和基於用戶當前瀏覽的物品的推薦,以及基於大衆喜愛的當下比較流行的物品都在不一樣的區域推薦給用戶,讓用戶能夠從全方位的推薦中找到本身真正感興趣的物品。探索推薦引擎內部的祕密,第 1 部分: 推薦引擎初探python

FP-tree推薦算法 是屬於上面第二條基於關聯規則推薦的算法,他一共只要 遍歷2次 原始數據就好了,比 apriori推薦算法複雜度會相對低一點,本文着重講解該算法的計算。web


按照網上最簡單的例子來進行分析,假設有事務數據以下:算法

寫入原始數據:app

info = [["E", "B", "C"], ["D", "C"], ["B", "A", "C"], ["B", "D"], ["D", "F", "C", "B"], ["E", "A", "C", "G"],["D", "G", "C"],["A", "E", "B"], ["B", "C", "D"], ["E", "C", "B", "D"]]

第一次遍歷原始數據,對原始數據進行計數,獲得:機器學習

{'G': 2, 'B': 7, 'D': 6, 'A': 3, 'E': 4, 'C': 8, 'F': 1}ide

python代碼爲:學習

# 遍歷數據,進行計數
def countitem(array):
    temp = []
    for item in array:
        for value in item:
            temp.append(value)

    # 寫入字典
    dict = {}
    for key in Counter(temp).keys():
        dict[key] = Counter(temp)[key]
    return dict

假設最小支持度爲 support = 3 ,剔除掉不知足的數據,獲得:code

{'A': 3, 'B': 7, 'E': 4, 'D': 6, 'C': 8}htm

剔除掉的數據爲:

['F', 'G']

python代碼爲:

# 刪除支持度不夠的key
def deletekey(dict, support):
    temp = dict.copy()
    detele = []
    for key in dict.keys():
        if dict[key] < support:
            temp.pop(key)
            detele.append(key)
    return temp, detele

第二次遍歷原始數據,構造FP-tree:

挖掘FP-tree,採用自底向上迭代方法,查找以A爲後綴的頻繁項集,而後是E,D,B,C。例如A的節點路徑爲:

('C', 8), ('B', 7), ('A', 1)
('C', 8), ('E', 4), ('A', 1)
('B', 7), ('E', 4), ('A', 1)

python代碼爲:

# info裏面元素的種類
def getkinds(array):
    temp = []
    for item in array:
        for value in item:
            if value in temp:
                pass
            else:
                temp.append(value)
    # ['C', 'B', 'E', 'D', 'A']
    # ['A', 'B', 'C', 'D', 'E']
    return sorted(temp)

# 獲得每個種類的全部路徑
def getrootpath(kinds, newinfo, dict):
    allinfo = {}
    for kind in kinds:
        kindarr = []
        for item in newinfo:
            # 若是這一條路徑包含某個種類
            itemarr = []
            if kind in item:
                for value in item:
                    if kind == value:
                        break
                    else:
                        itemarr.append(value)
            if itemarr:
                kindarr.append(itemarr)
        # print(kind, kindarr)
        # A [[('C', 8), ('B', 7)], [('C', 8), ('E', 4)], [('B', 7), ('E', 4)]]
        # B [[('C', 8)], [('C', 8)], [('C', 8)], [('C', 8)], [('C', 8)]]
        # C []
        # D [[('C', 8)], [('B', 7)], [('C', 8), ('B', 7)], [('C', 8)], [('C', 8), ('B', 7)], [('C', 8), ('B', 7)]]
        # E [[('C', 8), ('B', 7)], [('C', 8)], [('B', 7)], [('C', 8), ('B', 7), ('D', 6)]]
        allinfo[kind] = kindarr

    return allinfo

將節點路徑的count所有和A一致:

('C', 1), ('B', 1), ('A', 1)
('C', 1), ('E', 1), ('A', 1)
('B', 1), ('E', 1), ('A', 1)

統計全部字母種類,也就是:

{'E': 2, 'B': 2, 'CB': 1, 'C': 2, 'BE': 1, 'CE': 1}

沒有知足 support >= 3 ,因此A沒有強關聯的元素。

統計全部字幕種類的python代碼爲:

# 獲得全部組合的字典
def getrange(rootpath):
    alldict = {}
    for key in rootpath.keys():
        root = rootpath[key]
        # 一個元素的路徑
        onearr = []
        dict = {}

        # 實現一個元素路徑
        for item in root:
            for value in item:
                onearr.append(value)
                dict[value] = onearr.count(value)
        alldict[key] = dict
        # {'B': {'C': 5}, 'C': {}, 'E': {'C': 3, 'B': 3, 'D': 1}, 'A': {'E': 2, 'C': 2, 'B': 2}, 'D': {'C': 5, 'B': 4}}

        # 實現多個元素路徑
        for item1 in root:
            tempdict = {}
            for item2 in root:
                if item1 == item2:
                    if len(item1) > 1:
                        x = "".join(item1)
                        if x in tempdict.keys():
                            tempdict[x] += 1
                        else:
                            tempdict[x] = 1
            # print(tempdict)
            if tempdict:
                for x in tempdict:
                    alldict[key][x] = tempdict[x]
    # print(alldict)
    # {'D': {'CB': 3, 'C': 5, 'B': 4}, 'A': {'E': 2, 'B': 2, 'CB': 1, 'C': 2, 'BE': 1, 'CE': 1}, 'E': {'D': 1, 'C': 3, 'CB': 1, 'B': 3, 'CBD': 1}, 'B': {'C': 5}, 'C': {}}

    return alldict

最後獲得置信度:

{'E': {'B': '3/7', 'C': '3/8'}, 'B': {'C': '5/8'}, 'D': {'B': '4/7', 'C': '5/8', 'CB': '3/5'}}

表明的意思是:

買了C人,有3/8機率買E,有5/8機率買B,有5/8機率買D,且買了C又買了B的人有3/5的機率買D

置信度的計算能夠參考上一篇博文:

apriori推薦算法

置信度的python代碼爲:

# 獲得每一個種類的置信度
def confidence(alldict, support, newinfo):
    newdict = {}
    for kind in alldict:
        copydict = alldict[kind].copy()
        for key in alldict[kind]:
            if alldict[kind][key] < support:
                copydict.pop(key)
        if copydict:
            newdict[kind] = copydict
    # print(newdict)
    # {'E': {'C': 3, 'B': 3}, 'B': {'C': 5}, 'D': {'C': 5, 'CB': 3, 'B': 4}}

    # 計算置信度
    for kind in newdict:
        for key in newdict[kind].keys():
            tempnum = newdict[kind][key]
            denominator = 0
            for item in newinfo:
                if len(key) == 1:
                    if key in item:
                        denominator += 1
                elif len(key) == 2:
                    if key[0] in item and key[1] in item:
                        denominator += 1
                elif len(key) == 3:
                    if key[0] in item and key[1] in item and key[2] in item:
                        denominator += 1

            newdict[kind][key] = str(tempnum) + "/" + str(denominator)
    return newdict

全部源碼都在:

TTyb

相關文章
相關標籤/搜索