###推薦系統 推薦系統的核心問題就在於爲用戶推薦與其興趣類似度比較高的商品。好比在微博上,用戶至上想打發時間,並非想準確的查看某條信息,在首頁中查看每一條微博,爲了幫助他篩選出一批他們可能感興趣的信息,此時就須要分析出該用戶的興趣,從海量信息中選擇出與用戶興趣類似的信息,並將這些信息推薦給用戶。推薦系統就是這樣,根據用戶的歷史和社交狀況推薦與其喜愛相符的商品或信息。 這時候就須要一個類似度函數,函數能夠計算商品和我用戶之間的複雜度,向用戶推薦類似度較高的商品。爲了可以預測出函數,能夠利用到歷史詩句主要有:用戶的歷史行爲數據,與該用戶相關的其餘用戶信息,商品之間的類似性,文本描述等等。假設集合表示全部的用戶,集合表示全部須要推薦的商品。函數表示商品s到用戶c之間的有效用函數,例如:$$f:CxS->R$$其中,R是一個全體排序集合。對於每個用戶,但願從商品的集合上選擇出商品,即,以使得應用函數的值最大。html
在功業場景通常都是這樣,線下部分能夠隨意發揮,Python,MATLAB等等均可以,可是到線上部分就要考慮各類狀況了,好比效率和並不是,甚至是可移植可拓展性等等。 ###推薦系統的評估方法 ####準確度 這個概念應該比較熟悉的了,對於準確度的評估,也要分系統來看,推薦系統有兩種,一種是 打分系統,一種就是 TopN系統。打分系統其實就至關因而一種擬合方法,擬合用戶的打分過程,而TopN系統就是給出前N個好的商品而已,因此這兩個的準確度的評判標準是不同的。**對於打分系統:設 爲用戶 對物品 的實際打分, 爲預測得分,偏差斷定標準有兩個:$$RMSE=\sqrt{\frac{\sum_{u,i \in T}(r_{ui}-r_{ui}')^2}{|T|}}$$以上就是一些主要的推薦評價指標,固然仍是不少,好比新穎度,驚喜度,信任度,實時性等等。 ####冷啓動 冷啓動指的就是在一個新用戶和新商品進來的時候,推薦系統對這個用戶和商品是一無所知的,如何在這種狀況下作到有效的推薦,這就叫作冷啓動問題了。對於一個一無所知的用戶,解決方法有不少:能夠收集一些很是熱門的商品,收集一些信息,在用戶註冊的時候收集一些信息,好比彈出來問一下你喜歡什麼,或者問一下你感興趣的是什麼。不少遊戲知乎都會有這種舉措。在用戶結束以後還能夠進行一些互動的小遊戲來肯定用戶喜歡仍是不喜歡。 對於新商品,能夠根據自己的屬性,求與原來商品類似度。能夠用item-based-CF推薦出去。 ###類似度的衡量 歐式距離,是我的都知道,不提了。 Pearson Correlation類似度:$$Corr(x,y) = \frac{<x-x',y-y'>}{|x-x'||y-y'|}$$<x,y>指的就是內積操做、皮爾遜類似度的好處就在於對於級數不敏感,級數相差過大帶來的影響不大。 餘弦類似度:$$cos(x,y) = \frac{<x,y>}{|x||y|}$$這個就不用多說了,通常就是用在了文本編碼以後的向量類似度比較,由於這時候不少向量都不在歐式空間上了,通常就用他們夾角的大小來 ###推薦算法 ####基於內容的推薦 ####基於關聯規則的推薦 ####協同過濾的推薦 ####基於知識的推薦 ####基於圖的推薦 ####組合推薦 固然不會講解這麼多,只會提到一兩個。 ####基於內容的推薦系統 基於內容就是基於用戶喜歡的物品的屬性/內容進行推薦,須要分析內容,無需考慮用戶和用戶直接的關係。一般就是在文本相關的產品上進行推薦。因此通常就是經過內容上的關鍵詞進行推薦,而後編碼比對物品內容的異同進行推薦。事實上編碼以後就能夠隨意發揮了,直接使用KNN都是能夠的。 最簡單的文本推薦,對於一份文本,首先就是要創建資料這個時候就是叫編碼過程了,由於不可能把裏面的文字都抽取出來,這樣工做量很是大,使用首先就是要分詞去掉重複的詞語,而後抽取關鍵字作編碼。TF-IDF,詞袋模型,ont-hot編碼,詞在文件中權重都是能夠的,獲得這些向量以後,就能夠用類似度衡量,選擇合適的算法作類似度排序選擇了。好比對於書本**《Building data mining application for CRM》**這個本書感興趣。node
以上是商品總和。 出現過的單詞扣一,沒有的都是0,這種編碼叫作one-hot編碼,這裏商品少,單詞也就那麼幾個,因此ont-hot編碼不長,就是一點點而已。比較牛逼點的就是TF-IDF了: 把文檔出現詞的機率算了進來。獲得這些向量以後只須要作近似就行了,好比KNN最簡單的。 ####協同過濾的推薦 NeiNeighborhood-based Algorithm是一種基於近鄰的推薦,協同過濾有兩種,一種是基於用戶的協同過濾,一種是基於物品的協同過濾。 #####user-based CF 其實過程是很是簡單的,簡單到飛起。首先咱們是要獲得一個類似度矩陣,這個類似度矩陣首先是一個對稱的,其次它的對角線都是0,。計算完用戶之間的類似度以後利用用戶之間的類似度爲沒有打分的項打分。其實就是$$p(u,i) = \sum_{v \in N(j)}w_{u,v}r_{v,j}$$找到當前這個用戶沒有打分的商品,而後把對這個商品評價過的用戶的得分乘上類似矩陣的對應權重相加便可。 代碼實現 工具包的實現: 求餘弦類似度:def cos_sim(x, y):
numerator = x * y.T
denominator = np.sqrt(x * x.T)
return (numerator / denominator)[0, 0]
複製代碼
求類似度矩陣:git
def similarity(data):
m = np.shape(data)[0]
w = np.mat(np.zeros((m, m)))
for i in range(m):
for j in range(i, m):
if j != i:
w[i, j] = cos_sim(data[i, ], data[j, ])
w[j, i] = w[i, j]
else:
w[i, j] = 0
return w
複製代碼
求top N的商品是什麼:github
def top_k(predict, k):
top_recom = []
len_result = len(predict)
if k >= len_result:
top_recom = predict
else:
for i in range(k):
top_recom.append(predict[i])
return top_recom
複製代碼
基於用戶的協同過濾:算法
def user_based_recommend(data, w, user):
m, n = np.shape(data)
interaction = data[user, ]
not_inter = []
for i in range(n):
if interaction[0, i] == 0:
not_inter.append(i)
predict = {}
for x in not_inter:
item = np.copy(data[:, x])
for i in range(m):
if item[i, 0] != 0:
if x not in predict:
predict[x] = w[user, i] * item[i, 0]
else:
predict[x] = predict[x] + w[user, i] * item[i, 0]
return sorted(predict.items(), key=lambda d:d[1], reverse=True)
複製代碼
類似度矩陣
爲每個用戶所推薦的商品。 #####item_based CF 也是同樣,只須要把數據轉置一下就行了。
def item_based_recommend(data, w, user):
m, n = np.shape(data)
interation = data[:, user]
not_inter = []
for i in range(n):
if interation[0, i] == 0:
not_inter.append(i)
predict = {}
for x in not_inter:
item = np.copy(interation)
for j in range(m):
if item[0, j] != 0:
if x not in predict:
predict[x] = w[x, j] * item[0, j]
else:
predict[x] = predict[x] + w[x, j] * item[0, j]
return sorted(predict.items(), key=lambda d:d[1], reverse=True)
複製代碼
類似度矩陣
每位用戶的推薦。
###user-based vs item-based 這兩種方法各有優缺點。對於UserCF,適用於用戶較少的場景,若是用戶是很是多的的狀況下,計算用戶類似度矩陣的代價是很大的。這個時候若是物品相對用戶要少,那麼就能夠用ItemCF來計算類似度矩陣。對於兩種算法的領域也有很大的區別,UserCF的時效性較強,對於用戶興趣不太明顯的領域是有可能會推薦出來的,也就是說覆蓋性會好一些,由於它是根據用戶之間的類似度決定的,用戶之間的興趣點是類似可是不會都相同的,因此能夠削弱馬太效應。而對於ItemCF,這個物品類似度是死的,類似的基本都很類似,因此可能會有很大的長尾,通常是用戶需求很強烈的地方使用。還有冷啓動問題,對於一個新用戶進來的時候,不能馬上對他進行推薦,由於用戶的類似度矩陣是一段時間後離線計算的,新物品上線以後一旦有用戶對這個商品產生行爲就能夠將物品推薦給它產生行爲的用戶了。可是這樣就沒有辦法在不離線更新類似度表的狀況下將新物品推薦給用戶了。還有就是推薦理由,對於UserCF,用一個我根本不認識的人的習慣來推薦給我,對於用戶的說服力確定是不夠的,商品就不同了,商品是死的。 ###CF的優缺點 優勢:基於用戶的行爲對於推薦內容是不須要先驗知識的,只須要創建用戶或者是商品的類似矩陣便可,結構很簡單,在用戶豐富的狀況下效果很好,並且很簡單。 缺點:須要大量的行爲,也就是歷史數據,須要經過徹底相同的商品關聯起來,類似的不行。並且·使用CF是有前提的了,要求就是用戶只會徹底取決於以前的行爲,上下文是沒有關係的了。並且在數據稀疏的狀況下效果是很差的,還可能須要二度關聯,由於若是一下商品沒有什麼人買,基本就沒得推薦了。 ###基於隱語義的推薦 基於隱語義的推薦,其實就是矩陣分解。以前寫過一篇叫Matrix Factorization的文章講的就是這個:www.jianshu.com/p/af4905383… 首先對用戶進行一些簡單的編碼,由於用戶若是是把名字記上去是作不了計算的,因此咱們把用戶進行編碼,好比有4個用戶,一號用戶就,二號等等以此類推。bash
若是是使用神經網絡來解決這個問題,首先就是要設計一個網絡, ,N輸入用戶的數量,d就是網絡的維度,M就是輸出的結果,M就是物品的數量,由於最後的輸出就是用戶對商品的評分。 但實際上仍是有一個問題,就是對於激活函數,也就是非線性函數是否須要的問題。事實上是不須要的,由於若是隻有一個 是有效的,那麼這個 就是隻有一行有效的,因此只會有一個x通過了tanh函數,從效果上講一個tanh(x)和x是沒有什麼區別的。因此能夠忽略非線性: 整合一下公式$$h(x) = W^TVx$$因爲x就是一行有效,因此$$h(x) = W^Tv_n$$因此,第m個用戶的第n個商品的評分就是$$r_{nm} = w_{m}^Tv_n$$ 這樣就分解獲得了咱們要的公式,最後求導便可。事實上分解出來的兩個矩陣裏面的變量表明的數據的意義實際上是不明確的,也就是說比較抽象,怎麼想象都行。分解出來的矩陣 ,k表明的就是分解的度,分解的越多有可能會過擬合,因此這裏也是能夠加正則化的。 不要嘗試的去理解全部分解的贏語義,這是沒有意義的,好比神經網絡的每個神經元,事實上大家是不知道他們究竟是在幹什麼,只是知道他們在觀察而又,這裏也是同樣的,這裏面分解出來的東西,若是是電影,你能夠說是喜劇成分,武大成分,也能夠說是演員等等,至關於一指示變量而已,只是指明瞭這個物品是多少分,可是沒有給出具體的意義。 具體的公式以前的博客都有,例子也提到,這裏就不重複了。 ####上面提到的只是最簡單的MF模型,可是這類模型有一個缺點,他們分解出來的東西會有負數,這就尷尬了,由於不多有變量因素會其負做用的,因而便出現了非負矩陣分解。 非負矩陣分解出現的根本緣由就矩陣分解解釋性差的問題。 ###NMF 矩陣非負分解,這個就有點厲害了。首先引入一下KL離散度:$$D(A|B) = \sum_{i,j}(A_{i,j}log \frac{A}{B}-A_{i,j}+B_{i,j})$$###KL損失函數 **對於KL散度的推導其實很簡單:網絡
因此更新方式:$$Q = Q + n*[(P^TR) - (P^TPQ)]$$要作的就是設計一個n,使得乘上以後能夠抵消前面的Q便可。,帶進去以後:$$Q = Q \frac{(P^TR)}{(P^TPQ)} \ P = P \frac{(RQ^T)}{PQQ^T}$$使用KL離散也是同樣的。 ####代碼實現app
def train(V, r, maxCycles, e):
m, n = np.shape(V)
W = np.mat(np.random.random((m, r)))
H = np.mat(np.mat(np.random.random((r, n))))
for step in range(maxCycles):
V_pre = W * H
E = V - V_pre
err = 0.0
for i in range(m):
for j in range(n):
err += E[i, j] * E[i, j]
if err < e:
break
if step % 1000 == 0:
print("\Interator: ", step, " Loss: ", err)
a = W.T * V
b = W.T * W * H
for i in range(r):
for j in range(n):
if b[i, j] != 0:
H[i, j] = H[i, j] * a[i, j] / b[i, j]
c = V * H.T
d = W * H * H.T
for i in range(m):
for j in range(r):
if d[i, j] != 0:
W[i, j] = W[i, j] * c[i, j] / d[i, j]
return W, H
複製代碼
效果: dom
效果仍是能夠的。 ####CF VS隱語義 隱語義其實還有一種分解方式,就是SVD,SVD也能夠的,可是SVD的分解是,並且若是原矩陣是有不少缺省值的話,那麼SVD就會用0填充,這樣不太好的。相比之下CF跟簡單,並且可解釋性也強,可是隱語義模型能夠挖掘出更深層的物體或者是用戶之間的關係,覆蓋性會更好,雙方各有優缺點。 ###基於圖的推薦 ###PageRank Algorithm 首先要提到的就是PageRank算法,等下還要改進一下這個算法纔會獲得真正的推薦系統算法。這個算法是在Google初期使用的一個網頁排序算法,用於對網頁重要性的排序。一開始的網頁排序都是按照人工篩選或者是關鍵詞篩選的,可是這樣效率不高並且效果很差,常常是有不少網頁有不少重複關鍵詞的而後被置頂,這個時候就須要一個新的方法來從新評估網頁的質量,從新排序了。 把互聯網上的網頁模擬成一個節點,出鏈就是指向其餘網頁的一條有向邊,也就是當前這個網頁有一條指向其餘網頁的邊,入鏈就是一個指向當前頁面的邊,也就是說有一個網頁是指向了當前這個網頁的。這個時候當前網頁就是其餘網頁轉進來的了。 因此網頁評估是帶有如下的兩個假設的:數量假設:一個網頁的入度,也就是入鏈越大,質量越高。質量假設:一個節點的入度來源質量越高,那麼當前節點質量就越高。可是,問題來了,網頁A和網頁B的質量有關係,網頁B又和網頁C有關係,以此類推要是網頁C又和A有關係那就陷入了循環裏面了。這樣就解不出來了,因此簡化一下模型,假設,全部的網頁都和前一個網頁有關係,這樣就叫隨機遊走模型,也就是一階馬爾科夫模型。隨機遊走能夠看作是馬爾科夫鏈的一種特例。也叫作醉漢模型,沒一次走的方向或者步數只於前一次走的有關係而已,這一點有點像布朗運動。 如今將這個模型數學化一下下,假設如今有N個網頁,一開始初始化確定每個網頁的機率都是同樣大的,都是 ,好比下圖: 每個網頁的機率就是 ,每個網頁轉向其餘網頁的機率都是同樣的:記這個矩陣爲矩陣,表明的就網頁j跳轉到網頁i的機率,。根據這個矩陣,咱們是能夠計算出用戶訪問每個網頁的機率:ide
對於收斂性,有三個性質要證實的: #####存在一個特徵值 假設一個向量,因爲每一列相加都是1,因此$$1_n^TT = 1_n^T = A^T1_n = 1_n$$這個是直接根據性質證實的。 #####存在的特徵值都是 假設一個函數,假設表明的就是列向量,那麼有:$$s(T^2_l) = s(\sum_{i=1}^na_iali) = \sum_{i=1}^n s(a_i)a_{li} = \sum_{i=1}^na_{li} = 1$$因此,就仍是馬爾科夫矩陣,不管上面疊多少次方都仍是。根據特徵值的冪還有特徵向量有$$T^n x = \lambda^n x$$ ,若是那麼就是無限大了,可是馬爾科夫矩陣是小於1的,因此和假設矛盾。 #####收斂性