今天我們将要讨論的内容是資料科學和圖推薦graph recommendations:
第一個很簡單 - 将 cypher 用于社交推薦。接下來,我們将看一看相似性推薦,這涉及到可被計算的相似性度量,最後探索的是叢集推薦。
<a target="_blank"></a>
下面的資料集包含所有達拉斯 fort worth 國際機場的餐飲場所,達拉斯 fort worth 國際機場是美國主要的機場樞紐之一:

我們把節點标記成黃色并按照出入口和航站樓給它們的位置模組化。同時我們也按照食物和飲料的主類别将地點分類,其中一些包括墨西哥食物、三明治、酒吧和烤肉。
讓我們做一個簡單的推薦。我們想要在機場的某一确定地點找到一種特定食物,大括号中的内容表示是的使用者輸入,它将進入我們的假想應用程式中。
這個英文句子表示成 cypher 查詢:
這将提取出該類别中使用者所請求的所有地點、航站樓和出入口。然後我們可以計算出使用者所在位置到出入口的準确距離,并以升序傳回結果。再次說明,這個非常簡單的 cypher 推薦僅僅依據的是使用者在機場中的位置。
讓我們來看一下社交推薦。在我們的假想應用程式中,使用者可以登入并且可以用和 facebook 類似的方式标記自己“喜好”的地點,也可以在某地簽到。
考慮位于我們所研究的第一個模型之上的資料模型,現在讓我們在下面的分類中找到使用者的朋友喜好的航站樓裡面離出入口最近的餐飲場所:
<code>match</code> 子句和我們第一次 cypher 查詢的 <code>match</code> 子句相似,隻是現在我們依據喜好和朋友來比對:
前三行是完全一樣的,但是現在要考慮的是那些登入的使用者,我們想要通過 <code>:friends_with</code> 這一關系來找到他們的朋友。僅需通過在 cypher 中增加一些行内容,我們現在已經把社交層面考慮到了我們的推薦引擎中。
再次說明,我們僅僅顯示了使用者明确請求的類别,并且這些類别中的地點與使用者進入的地方是相同的航站樓。當然,我們希望按照登入并做出請求的使用者來濾過這些目錄,然後傳回地點的名字、位置以及所在目錄。我們也要顯示出有多少朋友已經“喜好”那個地點以及那個地點到出入口的确切距離,然後在<code>return</code> 子句中同時傳回所有這些内容。
現在,讓我們看一看相似性推薦引擎:
和前面的資料模型相似,使用者可以标記“喜好”的地點,但是這一次他們可以用 1 到 10 的整數給地點評分。這是通過前期在 neo4j 中增加一些屬性到關系中模組化實作的。
這将允許我們找到其他相似的使用者,比如以上面的 greta 和 alice 為例,我們已經查詢了他們共同喜好的地點,并且對于每一個地點,我們可以看到他們所設定的權重。大概地,我們可以通過他們的評分來确定他們之間的相似性大小。
現在我們有兩個向量:
現在讓我們按照歐幾裡得距離euclidean distance的定義來計算這兩個向量之間的距離:
我們把所有的數字帶入公式中計算,然後得到下面的相似度,這就是兩個使用者之間的“距離”:
你可以很容易地在 cypher 中計算兩個特定使用者的“距離”,特别是如果他們僅僅同時“喜好”一個很小的地點子集。再次說明,這兒我們依據兩個使用者 alice 和 greta 來進行比對,并嘗試去找到他們同時“喜好”的地點:
他們都有對最後找到的地點的 <code>:likes</code> 關系,然後我們可以在 cypher 中很容易的計算出他們之間的歐幾裡得距離,計算方法為他們對各個地點評分差的平方求和再開平方根。
在兩個特定使用者的例子中上面這個方法或許能夠工作。但是,在實時情況下,當你想要通過和實時資料庫中的其他使用者比較,進而由一架飛機上的一個使用者推斷相似使用者時,這個方法就不一定能夠工作。不用說,至少它不能夠很好的工作。
為了找到解決這個問題的好方法,我們可以預先計算好距離并存入實際關系中:
當遇到一個很大的資料集時,我們需要成批處理這件事,在這個很小的示例資料集中,我們可以按照所有使用者的迪卡爾乘積cartesian product和他們共同“喜好”的地點來進行比對。當我們使用 <code>where id(u1) < id(u2)</code> 作為 cypher 詢問的一部分時,它隻是來确定我們在左邊和右邊沒有找到相同的對的一個技巧。
通過使用者之間的歐幾裡得距離,我們建立了他們之間的一種關系,叫做 <code>:distance</code>,并且設定了一個叫做 <code>euclidean</code> 的歐幾裡得屬性。理論上,我們可以也通過使用者間的一些關系來存儲其他相似度進而擷取不同的相似度,因為在确定的環境下某些相似度可能比其他相似度更有用。
在 neo4j 中,的确是對關系屬性模組化的能力使得完成像這樣的事情無比簡單。然而,實際上,你不會希望存儲每一個可能存在的單一關系,因為你僅僅希望傳回離他們“最近”的一些人。
是以你可以根據一些臨界值來存入前幾個,進而你不需要建構完整的連通圖。這允許你完成一些像下面這樣的實時的資料庫查詢,因為我們已經預先計算好了“距離”并存儲在了關系中,在 cypher 中,我們能夠很快的攫取出資料。
在這個查詢中,我們依據地點和類别來進行比對:
再次說明,前三行是相同的,除了登入使用者以外,我們找出了和他們有 <code>:distance</code> 關系的使用者。這是我們前面檢視的關系産生的作用 - 實際上,你隻需要存儲處于前幾位的相似使用者 <code>:distance</code> 關系,是以你不需要在 <code>match</code> 子句中攫取大量使用者。相反,我們隻攫取和那些使用者“喜好”的地方有 <code>:distance</code> 關系的使用者。
這允許我們用少許幾行内容表達較為複雜的模型。我們也可以攫取 <code>:likes</code> 關系并把它放入到變量中,因為後面我們将使用這些權重來評分。
在這兒重要的是,我們可以依據“距離”大小将使用者按照升序進行排序,因為這是一個距離測度。同時,我們想要找到使用者間的最小距離因為距離越小表明他們的相似度最大。
通過其他按照歐幾裡得距離大小排序好的使用者,我們得到使用者評分最高的三個地點并按照使用者的平均評分高低來推薦這些地點。換句話說,我們先找出一個活躍使用者,然後依據其他使用者“喜好”的地點找出和他最相似的其他使用者,接下來按照這些相似使用者的平均評分把那些地點排序在結果的集合中。
本質上,我們通過把所有評分相加然後除以收集的使用者數目來計算出平均分,然後按照平均評分的升序進行排序。其次,我們按照出入口距離排序。假想地,我猜測應該會有交接點,是以你可以按照出入口距離排序然後再傳回名字、類别、出入口和航站樓。
在這兒你可以使用一些統計軟體,把資料從 neo4j 取出然後放入像 apache spark、r 或者 python 這樣的軟體中。下面是一段把資料從 neo4j 中取出的 r 代碼,運作該程式,如果正确,寫下程式傳回結果的給 neo4j,可以是一個屬性、節點、關系或者一個新的标簽。
通過持續把程式運作結果放入到圖表中,你可以在一個和我們剛剛看到的查詢相似的實時查詢中使用它:
下面是用 r 來完成這件事的一些示例代碼,但是你可以使用任何你最喜歡的軟體來做這件事,比如 python 或 spark。你需要做的隻是登入并連接配接到圖表。
在下面的例子中,我基于使用者的相似性把他們聚合起來。每個使用者作為一個觀察點,然後得到他們對每一個目錄評分的平均值。
假定使用者對酒吧類評分的方式和一般的評分方式相似。然後我攫取出喜歡相同類别中的地點的使用者名、類别名、“喜好”關系的平均權重,比如平均權重這些資訊,進而我可以得到下面這樣一個表格:
因為我們把每一個使用者都作為一個觀察點,是以我們必須巧妙的處理每一個類别中的資料,這些資料的每一個特性都是使用者對該類中餐廳評分的平均權重。接下來,我們将使用這些資料來确定使用者的相似性,然後我将使用聚類clustering算法來确定在不同叢集中的使用者。
在 r 中這很直接:
在這個示例中我們使用k-均值k-means聚類算法,這将使你很容易攫取叢集配置設定。總之,我通過運作聚類算法然後分别得到每一個使用者的叢集配置設定。
bob 和 david 在一個相同的叢集中 - 他們在叢集二中 - 現在我可以實時檢視哪些使用者被放在了相同的叢集中。
接下來我把叢集配置設定寫入 csv 檔案中,然後存入圖資料庫:
我們隻有使用者和叢集配置設定,是以 csv 檔案隻有兩列。 <code>load csv</code> 是 cypher 中的内建文法,它允許你從一些其他檔案路徑或者 url 調用 csv ,并給它一個别名。接下來,我們将比對圖資料庫中存在的使用者,從 csv 檔案中攫取使用者列然後合并到叢集中。
我們在圖表中建立了一個新的标簽節點:<code>cluster id</code>, 這是由 k-平均聚類算法給出的。接下來我們建立使用者和叢集間的關系,通過建立這個關系,當我們想要找到在相同叢集中的實際推薦使用者時,就會很容易進行查詢。
我們現在有了一個新的叢集标簽,在相同叢集中的使用者和那個叢集存在關系。新的資料模型看起來像下面這樣,它比我們前面探索的其他資料模型要更好:
現在讓我們考慮下面的查詢:
通過這個 cypher 查詢,我們在更遠處找到了在同一個叢集中的相似使用者。由于這個原因,我們删除了“距離”關系:
在這個查詢中,我們取出已經登入的使用者,根據使用者-叢集關系找到他們所在的叢集,找到他們附近和他們在相同叢集中的使用者。
我們把這些使用者配置設定到變量 <code>c1</code> 中,然後我們得到其他被我取别名為 <code>neighbor</code> 變量的使用者,這些使用者和那個相同叢集存在着使用者-叢集關系,最後我們得到這些附近使用者“喜好”的地點。再次說明,我把“喜好”放入了變量 r 中,因為我們需要從關系中攫取權重來對結果進行排序。
在這個查詢中,我們所做的改變是,不使用相似性距離,而是攫取在相同叢集中的使用者,然後對類别、航站樓以及我們所攫取的登入使用者進行聲明。我們收集所有的權重:來自附近使用者“喜好”地點的“喜好”關系,得到的類别,确定的距離值,然後把它們按升序進行排序并傳回結果。
在這些例子中,我們可以進行一個相當複雜的處理并且将其放到圖資料庫中,然後我們就可以使用實時算法結果-聚類算法和叢集配置設定的結果。
我們更喜歡的工作流程是更新這些叢集配置設定,更新頻率适合你自己就可以,比如每晚一次或每小時一次。當然,你可以根據直覺來決定多久更新一次這些叢集配置設定是可接受的。
原文釋出時間為:2017-12-14
本文來自雲栖社群合作夥伴“linux中國”