推薦系統(tǒng)
推薦系統(tǒng)的核心問(wèn)題就在于為用戶推薦與其興趣相似度比較高的商品。比如在微博上,用戶至上想打發(fā)時(shí)間,并不是想準(zhǔn)確的查看某條信息,在首頁(yè)中查看每一條微博,為了幫助他篩選出一批他們可能感興趣的信息,此時(shí)就需要分析出該用戶的興趣,從海量信息中選擇出與用戶興趣相似的信息,并將這些信息推薦給用戶。推薦系統(tǒng)就是這樣,根據(jù)用戶的歷史和社交情況推薦與其喜好相符的商品或信息。
這時(shí)候就需要一個(gè)相似度函數(shù),函數(shù)
可以計(jì)算商品和我用戶之間的復(fù)雜度,向用戶推薦相似度較高的商品。為了能夠預(yù)測(cè)出函數(shù)
,可以利用到歷史詩(shī)句主要有:用戶的歷史行為數(shù)據(jù),與該用戶相關(guān)的其他用戶信息,商品之間的相似性,文本描述等等。假設(shè)集合
表示所有的用戶,集合
表示所有需要推薦的商品。函數(shù)
表示商品s到用戶c之間的有效用函數(shù),例如:
其中,R是一個(gè)全體排序集合。對(duì)于每一個(gè)用戶
,希望從商品的集合上選擇出商品,即
,以使得應(yīng)用函數(shù)
的值最大。

推薦系統(tǒng)的評(píng)估方法
準(zhǔn)確度
這個(gè)概念應(yīng)該比較熟悉的了,對(duì)于準(zhǔn)確度的評(píng)估,也要分系統(tǒng)來(lái)看,推薦系統(tǒng)有兩種,一種是打分系統(tǒng),一種就是TopN系統(tǒng)。打分系統(tǒng)其實(shí)就相當(dāng)于是一種擬合方法,擬合用戶的打分過(guò)程,而TopN系統(tǒng)就是給出前N個(gè)好的商品而已,所以這兩個(gè)的準(zhǔn)確度的評(píng)判標(biāo)準(zhǔn)是不一樣的。對(duì)于打分系統(tǒng):設(shè)為用戶
對(duì)物品
的實(shí)際打分,
為預(yù)測(cè)得分,誤差判定標(biāo)準(zhǔn)有兩個(gè):
對(duì)于TopN的推薦系統(tǒng),
代表推薦的內(nèi)容,
就是用戶選擇的內(nèi)容:
這兩個(gè)評(píng)價(jià)指標(biāo)是互相牽制的,準(zhǔn)確率高制約著召回率。
覆蓋率
表示對(duì)物體長(zhǎng)尾的發(fā)掘能力。有時(shí)候賣(mài)的多的物品會(huì)賣(mài)的更多,因?yàn)楹芏嗳丝吹絼e人也買(mǎi)就會(huì)跟風(fēng),但這樣就會(huì)造成窮的會(huì)更窮,富的會(huì)更富,所以為了消除這種兩極分化,也叫馬太效應(yīng)??梢杂靡粋€(gè)熵的概念來(lái)衡量熵其實(shí)是個(gè)人都知道,平均的時(shí)候是最大的,這就有利于消除貧富差距。
多樣性
多樣性表示的就是推薦物品的種類多樣程度,如果推薦的物品基本都是鞋子一類的,那么多樣性就很差了,首先用來(lái)表示這兩個(gè)物品的相似度,多樣性表示:
以上就是一些主要的推薦評(píng)價(jià)指標(biāo),當(dāng)然還是很多,比如新穎度,驚喜度,信任度,實(shí)時(shí)性等等。
冷啟動(dòng)
冷啟動(dòng)指的就是在一個(gè)新用戶和新商品進(jìn)來(lái)的時(shí)候,推薦系統(tǒng)對(duì)這個(gè)用戶和商品是一無(wú)所知的,如何在這種情況下做到有效的推薦,這就叫做冷啟動(dòng)問(wèn)題了。對(duì)于一個(gè)一無(wú)所知的用戶,解決方法有很多:可以收集一些非常熱門(mén)的商品,收集一些信息,在用戶注冊(cè)的時(shí)候收集一些信息,比如彈出來(lái)問(wèn)一下你喜歡什么,或者問(wèn)一下你感興趣的是什么。很多游戲知乎都會(huì)有這種舉措。在用戶結(jié)束之后還可以進(jìn)行一些互動(dòng)的小游戲來(lái)確定用戶喜歡還是不喜歡。
對(duì)于新商品,可以根據(jù)本身的屬性,求與原來(lái)商品相似度。可以用item-based-CF推薦出去。
相似度的衡量
歐式距離,是個(gè)人都知道,不提了。
Pearson Correlation相似度:<x,y>指的就是內(nèi)積操作、皮爾遜相似度的好處就在于對(duì)于級(jí)數(shù)不敏感,級(jí)數(shù)相差過(guò)大帶來(lái)的影響不大。
余弦相似度:這個(gè)就不用多說(shuō)了,一般就是用在了文本編碼之后的向量相似度比較,因?yàn)檫@時(shí)候很多向量都不在歐式空間上了,一般就用他們夾角的大小來(lái)
推薦算法
基于內(nèi)容的推薦
基于關(guān)聯(lián)規(guī)則的推薦
協(xié)同過(guò)濾的推薦
基于知識(shí)的推薦
基于圖的推薦
組合推薦
當(dāng)然不會(huì)講解這么多,只會(huì)提到一兩個(gè)。
基于內(nèi)容的推薦系統(tǒng)
基于內(nèi)容就是基于用戶喜歡的物品的屬性/內(nèi)容進(jìn)行推薦,需要分析內(nèi)容,無(wú)需考慮用戶和用戶直接的關(guān)系。通常就是在文本相關(guān)的產(chǎn)品上進(jìn)行推薦。所以一般就是通過(guò)內(nèi)容上的關(guān)鍵詞進(jìn)行推薦,然后編碼比對(duì)物品內(nèi)容的異同進(jìn)行推薦。事實(shí)上編碼之后就可以隨意發(fā)揮了,直接使用KNN都是可以的。
最簡(jiǎn)單的文本推薦,對(duì)于一份文本,首先就是要建立資料這個(gè)時(shí)候就是叫編碼過(guò)程了,因?yàn)椴豢赡馨牙锩娴奈淖侄汲槿〕鰜?lái),這樣工作量非常大,使用首先就是要分詞去掉重復(fù)的詞語(yǔ),然后抽取關(guān)鍵字做編碼。TF-IDF,詞袋模型,ont-hot編碼,詞在文件
中權(quán)重
都是可以的,得到這些向量之后,就可以用相似度衡量,選擇合適的算法做相似度排序選擇了。比如對(duì)于書(shū)本《Building data mining application for CRM》這個(gè)本書(shū)感興趣。

以上是商品總和。

出現(xiàn)過(guò)的單詞扣一,沒(méi)有的都是0,這種編碼叫做one-hot編碼,這里商品少,單詞也就那么幾個(gè),所以ont-hot編碼不長(zhǎng),就是一點(diǎn)點(diǎn)而已。比較牛逼點(diǎn)的就是TF-IDF了:

協(xié)同過(guò)濾的推薦
NeiNeighborhood-based Algorithm是一種基于近鄰的推薦,協(xié)同過(guò)濾有兩種,一種是基于用戶的協(xié)同過(guò)濾,一種是基于物品的協(xié)同過(guò)濾。
user-based CF
其實(shí)過(guò)程是非常簡(jiǎn)單的,簡(jiǎn)單到飛起。首先我們是要得到一個(gè)相似度矩陣,這個(gè)相似度矩陣首先是一個(gè)對(duì)稱的,其次它的對(duì)角線都是0,。計(jì)算完用戶之間的相似度之后利用用戶之間的相似度為沒(méi)有打分的項(xiàng)打分。其實(shí)就是找到當(dāng)前這個(gè)用戶沒(méi)有打分的商品,然后把對(duì)這個(gè)商品評(píng)價(jià)過(guò)的用戶的得分乘上相似矩陣的對(duì)應(yīng)權(quán)重相加即可。
代碼實(shí)現(xiàn)
工具包的實(shí)現(xiàn):
求余弦相似度:
def cos_sim(x, y):
numerator = x * y.T
denominator = np.sqrt(x * x.T)
return (numerator / denominator)[0, 0]
求相似度矩陣:
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的商品是什么:
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
基于用戶的協(xié)同過(guò)濾:
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)

相似度矩陣

為每一個(gè)用戶所推薦的商品。
item_based CF
也是一樣,只需要把數(shù)據(jù)轉(zhuǎn)置一下就好了。
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
這兩種方法各有優(yōu)缺點(diǎn)。對(duì)于UserCF,適用于用戶較少的場(chǎng)景,如果用戶是非常多的的情況下,計(jì)算用戶相似度矩陣的代價(jià)是很大的。這個(gè)時(shí)候如果物品相對(duì)用戶要少,那么就可以用ItemCF來(lái)計(jì)算相似度矩陣。對(duì)于兩種算法的領(lǐng)域也有很大的區(qū)別,UserCF的時(shí)效性較強(qiáng),對(duì)于用戶興趣不太明顯的領(lǐng)域是有可能會(huì)推薦出來(lái)的,也就是說(shuō)覆蓋性會(huì)好一些,因?yàn)樗歉鶕?jù)用戶之間的相似度決定的,用戶之間的興趣點(diǎn)是相似但是不會(huì)都相同的,所以可以削弱馬太效應(yīng)。而對(duì)于ItemCF,這個(gè)物品相似度是死的,相似的基本都很相似,所以可能會(huì)有很大的長(zhǎng)尾,一般是用戶需求很強(qiáng)烈的地方使用。還有冷啟動(dòng)問(wèn)題,對(duì)于一個(gè)新用戶進(jìn)來(lái)的時(shí)候,不能立刻對(duì)他進(jìn)行推薦,因?yàn)橛脩舻南嗨贫染仃囀且欢螘r(shí)間后離線計(jì)算的,新物品上線之后一旦有用戶對(duì)這個(gè)商品產(chǎn)生行為就可以將物品推薦給它產(chǎn)生行為的用戶了。但是這樣就沒(méi)有辦法在不離線更新相似度表的情況下將新物品推薦給用戶了。還有就是推薦理由,對(duì)于UserCF,用一個(gè)我根本不認(rèn)識(shí)的人的習(xí)慣來(lái)推薦給我,對(duì)于用戶的說(shuō)服力肯定是不夠的,商品就不一樣了,商品是死的。
CF的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):基于用戶的行為對(duì)于推薦內(nèi)容是不需要先驗(yàn)知識(shí)的,只需要建立用戶或者是商品的相似矩陣即可,結(jié)構(gòu)很簡(jiǎn)單,在用戶豐富的情況下效果很好,而且很簡(jiǎn)單。
缺點(diǎn):需要大量的行為,也就是歷史數(shù)據(jù),需要通過(guò)完全相同的商品關(guān)聯(lián)起來(lái),相似的不行。而且·使用CF是有前提的了,要求就是用戶只會(huì)完全取決于之前的行為,上下文是沒(méi)有關(guān)系的了。而且在數(shù)據(jù)稀疏的情況下效果是不好的,還可能需要二度關(guān)聯(lián),因?yàn)槿绻幌律唐窙](méi)有什么人買(mǎi),基本就沒(méi)得推薦了。
基于隱語(yǔ)義的推薦
基于隱語(yǔ)義的推薦,其實(shí)就是矩陣分解。之前寫(xiě)過(guò)一篇叫Matrix Factorization的文章講的就是這個(gè):http://www.itdecent.cn/p/af49053832c5
首先對(duì)用戶進(jìn)行一些簡(jiǎn)單的編碼,因?yàn)橛脩羧绻前衙钟浬先ナ亲霾涣擞?jì)算的,所以我們把用戶進(jìn)行編碼,比如有4個(gè)用戶,一號(hào)用戶就,二號(hào)
等等以此類推。

如果是使用神經(jīng)網(wǎng)絡(luò)來(lái)解決這個(gè)問(wèn)題,首先就是要設(shè)計(jì)一個(gè)網(wǎng)絡(luò),




具體的公式之前的博客都有,例子也提到,這里就不重復(fù)了。
上面提到的只是最簡(jiǎn)單的MF模型,但是這類模型有一個(gè)缺點(diǎn),他們分解出來(lái)的東西會(huì)有負(fù)數(shù),這就尷尬了,因?yàn)楹苌儆凶兞恳蛩貢?huì)其負(fù)作用的,于是便出現(xiàn)了非負(fù)矩陣分解。
非負(fù)矩陣分解出現(xiàn)的根本原因就矩陣分解解釋性差的問(wèn)題。
NMF
矩陣非負(fù)分解,這個(gè)就有點(diǎn)厲害了。首先引入一下KL離散度:
KL損失函數(shù)
對(duì)于KL散度的推導(dǎo)其實(shí)很簡(jiǎn)單:
所以一階Tayor逼近的誤差是:
代入熵
:
這樣推導(dǎo)出來(lái)了。平方差損失函數(shù)對(duì)應(yīng)著高斯分布,那么KL肯定也對(duì)應(yīng)著另一個(gè)分布——泊松分布:
因?yàn)?img class="math-inline" src="https://math.jianshu.com/math?formula=x" alt="x" mathimg="1">是隨機(jī)數(shù),所以求一下期望:
所以KL離散度就對(duì)應(yīng)了泊松分布。
對(duì)于這個(gè)KL離散度:KL離散度一定是大于等于0的,當(dāng)
的時(shí)候,這個(gè)離散度就是等于0的了,所以我們要求的就是不斷的
即可。
所以現(xiàn)在NMF的損失函數(shù)有兩種了①均方差損失函數(shù):;②KL離散度:
,還是用第一種吧!
問(wèn)題來(lái)了,既然是非負(fù)數(shù)的,怎么保證是正數(shù)是一個(gè)問(wèn)題,這里有一個(gè)很牛逼的技巧:
所以更新方式:要做的就是設(shè)計(jì)一個(gè)n,使得乘上之后可以抵消前面的Q即可。
,帶進(jìn)去之后:
使用KL離散也是一樣的。
代碼實(shí)現(xiàn)
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
效果:

效果還是可以的。
CF VS隱語(yǔ)義
隱語(yǔ)義其實(shí)還有一種分解方式,就是SVD,SVD也可以的,但是SVD的分解是,而且如果原矩陣是有很多缺省值的話,那么SVD就會(huì)用0填充,這樣不太好的。相比之下CF跟簡(jiǎn)單,而且可解釋性也強(qiáng),但是隱語(yǔ)義模型可以挖掘出更深層的物體或者是用戶之間的關(guān)系,覆蓋性會(huì)更好,雙方各有優(yōu)缺點(diǎn)。
基于圖的推薦
PageRank Algorithm
首先要提到的就是PageRank算法,等下還要改進(jìn)一下這個(gè)算法才會(huì)得到真正的推薦系統(tǒng)算法。這個(gè)算法是在Google初期使用的一個(gè)網(wǎng)頁(yè)排序算法,用于對(duì)網(wǎng)頁(yè)重要性的排序。一開(kāi)始的網(wǎng)頁(yè)排序都是按照人工篩選或者是關(guān)鍵詞篩選的,但是這樣效率不高而且效果不好,經(jīng)常是有很多網(wǎng)頁(yè)有很多重復(fù)關(guān)鍵詞的然后被置頂,這個(gè)時(shí)候就需要一個(gè)新的方法來(lái)重新評(píng)估網(wǎng)頁(yè)的質(zhì)量,重新排序了。
把互聯(lián)網(wǎng)上的網(wǎng)頁(yè)模擬成一個(gè)節(jié)點(diǎn),出鏈就是指向其他網(wǎng)頁(yè)的一條有向邊,也就是當(dāng)前這個(gè)網(wǎng)頁(yè)有一條指向其他網(wǎng)頁(yè)的邊,入鏈就是一個(gè)指向當(dāng)前頁(yè)面的邊,也就是說(shuō)有一個(gè)網(wǎng)頁(yè)是指向了當(dāng)前這個(gè)網(wǎng)頁(yè)的。這個(gè)時(shí)候當(dāng)前網(wǎng)頁(yè)就是其他網(wǎng)頁(yè)轉(zhuǎn)進(jìn)來(lái)的了。所以網(wǎng)頁(yè)評(píng)估是帶有以下的兩個(gè)假設(shè)的:數(shù)量假設(shè):一個(gè)網(wǎng)頁(yè)的入度,也就是入鏈越大,質(zhì)量越高。質(zhì)量假設(shè):一個(gè)節(jié)點(diǎn)的入度來(lái)源質(zhì)量越高,那么當(dāng)前節(jié)點(diǎn)質(zhì)量就越高。但是,問(wèn)題來(lái)了,網(wǎng)頁(yè)A和網(wǎng)頁(yè)B的質(zhì)量有關(guān)系,網(wǎng)頁(yè)B又和網(wǎng)頁(yè)C有關(guān)系,以此類推要是網(wǎng)頁(yè)C又和A有關(guān)系那就陷入了循環(huán)里面了。這樣就解不出來(lái)了,所以簡(jiǎn)化一下模型,假設(shè),所有的網(wǎng)頁(yè)都和前一個(gè)網(wǎng)頁(yè)有關(guān)系,這樣就叫隨機(jī)游走模型,也就是一階馬爾科夫模型。隨機(jī)游走可以看做是馬爾科夫鏈的一種特例。也叫做醉漢模型,沒(méi)一次走的方向或者步數(shù)只于前一次走的有關(guān)系而已,這一點(diǎn)有點(diǎn)像布朗運(yùn)動(dòng)。
現(xiàn)在將這個(gè)模型數(shù)學(xué)化一下下,假設(shè)現(xiàn)在有N個(gè)網(wǎng)頁(yè),一開(kāi)始初始化肯定每一個(gè)網(wǎng)頁(yè)的概率都是一樣大的,都是,比如下圖:

記這個(gè)矩陣為







