概覽
- 使用場景
- 直觀解釋
- 計算 & 拓展
- 舉個栗子(python)
- 算法復雜度
最后真推薦歌了~
使用場景
想象一個做協同過濾的推薦場景,想象不出來看下圖~
先試試傳統的基于物品的協同過濾(cf)方法,用戶1喜歡搖滾和輕音樂,簡單認為搖滾和輕音樂是相似的。同理用戶2喜歡輕音樂和民謠,簡單認為輕音樂和民謠相似。
最后計算item間相似度的時候,和搖滾相似的是輕音樂,和民謠相似的是輕音樂,傳統的基于item的cf是發現不了搖滾和民謠的相似性的。
這里就不考慮基于用戶的cf了,確實基于用戶的cf是可以發現搖滾和民謠的關系滴~
這里帶入SimRank的思想
Two objects are similar if they are related to similar objects.
這里物品的關系由消費物品的用戶來表達。
從用戶1和用戶2的歷史記錄里面得到的 搖滾 - 輕音樂 - 民謠 的關系,可以得到搖滾和民謠的相似度
說明 SimRank 的思想可以發現 ItemCF 發現不了的 item 相似關系
直觀解釋
定義與公式
item-item關系圖
節點a關聯到節點b的關系
節點a的鄰居節點集合,即所有指向a的節點集合
節點間相似度s(a,b),C是衰減因子,經驗取值為0.8
復現計算過程
6個用戶收聽5首歌的情景,通過log生成左邊的二部圖,再通過用戶作為聯系生成右邊的item關系圖
按照相似度公式依次計算每個節點,發現I2和I4有共同的入度節點I1,就是從(I1,I1)發現了(I2,I4)
依次進行n輪計算,圖中標明了每輪計算新發現的關系,每次新發現的關系又可以反補給以前發現的關系,作為增強
可以發現第一輪發現的關系類似于推薦理由“喜歡x的用戶也喜歡y”,這種第一輪計算發現的關系可以看作item之間的一次跳躍,暫時稱作一跳關系,第二輪迭代發現的(I3,I5)可以看做是2條關系,第n輪拓展的為n跳關系
基于MR模型的計算方法
map階段
去尋找每個節點的相鄰節點,即尋找I(a)里,I(b)里所有點的相似度,從而計算s(a,b)
reduce階段
根據計算結果更新全局的相似度
拓展的simrank
打開方法:自行google
- delta-simrank
- simrank++
計算方式的拓展
- 深度優先搜索
- 基于矩陣乘法的計算
python的local Example
G = nx.read_graphml("/Users/Matter/paper_code/simrank/widom.graphml")
r=0.8
max_iter=10
eps=1e-4
nodes = G.nodes() #['1', '0', '3', '2', '4']
pred_func = G.predecessors if isinstance(G, nx.DiGraph) else G.neighbors
# nodes_i {'0': 1, '1': 0, '2': 3, '3': 2, '4': 4}
nodes_i = {nodes[i]: i for i in range(0, len(nodes))}
sim_prev = numpy.zeros(len(nodes)) # array([ 0., 0., 0., 0., 0.])
sim = numpy.identity(len(nodes))
# ### 單位矩陣
# array([[ 1., 0., 0., 0., 0.],
# [ 0., 1., 0., 0., 0.],
# [ 0., 0., 1., 0., 0.],
# [ 0., 0., 0., 1., 0.],
# [ 0., 0., 0., 0., 1.]])
# ###
# round 1
sim_prev = numpy.copy(sim)
for u, v in itertools.product(nodes, nodes):
if u==v:continue
u_ps, v_ps = pred_func(u), pred_func(v)
s_uv = 0
for u_n, v_n in itertools.product(u_ps, v_ps):
s_uv += sim_prev[nodes_i[u_n]][nodes_i[v_n]]
sim[nodes_i[u]][nodes_i[v]] = (r * s_uv) / (len(u_ps) * len(v_ps) + DIV_EPS)
對應圖的結構
<?xml version="1.0" encoding="utf-8"?><graphml xmlns="[http://graphml.graphdrawing.org/xmlns](http://graphml.graphdrawing.org/xmlns)" xmlns:xsi="[http://www.w3.org/2001/XMLSchema-instance](http://www.w3.org/2001/XMLSchema-instance)" xsi:schemaLocation="[http://graphml.graphdrawing.org/xmlns](http://graphml.graphdrawing.org/xmlns) [http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd](http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd)">
<graph edgedefault="directed">
<node id="0" />
<node id="1" />
<node id="2" />
<node id="3" />
<node id="4" />
<edge source="0" target="1" />
<edge source="2" target="0" />
<edge source="1" target="2" />
<edge source="0" target="3" />
<edge source="3" target="4" />
<edge source="4" target="3" />
</graph>
</graphml>
算法復雜度
n_i:item的數量
n:item對的數量,大概是n_i * n_i
neighbor:每個item的平均鄰居數量
d:每一對vid對里的結點鄰居平均數量乘積,大概 neighbor * neighbor
一輪迭代的空間復雜度:O(n*n)
一輪迭代的空間復雜度:O(n*n*d)
對應到item數量就是O(n_i * n_i * n_i * n_i)的復雜度
簡而言之就是item做笛卡爾得到item pair,再對item pair做笛卡爾
后記
- 我是敗給復雜度了
- 最開始的例子,我被推薦了一首Fool's Day,循環到手機沒電的節奏
http://music.163.com/#/song?id=3951074