動手構建一個推薦系統(Recommendation System)

來源:互聯網
上載者:User
文章目錄
  • (1)資料集
  • (2)核心:推薦函數
  • (3)實驗結果

寫在前面:本文通過構建一個電影推薦系統,深入淺出的介紹推薦系統相關的概念、演算法,讓讀者朋友能夠在對推薦系統有比較全面的認識的基礎之上,能夠輕鬆地構建出自己的推薦系統。

1. 什麼是推薦系統(Recommendation System)

推薦系統是指根據一個群體的偏好,來為群體中的成員提供推薦的系統。現實生活中這樣的例子很多,比如豆瓣(Douban.com)讀書中的“豆瓣猜”功能,它根據你看過的一些書和相關評價,與整個豆瓣社區其它會員看過的書與評價經過一系列的計算,就能給你推薦一些你沒有讀過的,但有可能感興趣的書(如所示):
這是我讀過的或者正在讀的書:

這是豆瓣給我推薦的書:

通過上面的例子,相信大家對推薦系統都有了一個初步的認識。其實生活中還有許許多多的這樣的例子,像線上購物中的商品推薦、線上視頻播放網站的視頻推薦等。

2. 推薦系統相關理論

(1)推薦系統通常可以分為兩類:一類是基於人的推薦系統,它利用人與人之間的相似性來進行推薦;一類是基於物品的推薦,它利用物品之間的相似性來進行推薦。通俗地講,基於人的推薦,是通過分析人與人喜歡的物品,計算出人與人之間的相似性,然後做推薦;而基於物品的推薦,是通過分析某人喜歡的物品與其它物品的相似性,然後來為其做推薦。
(2)推薦系統中比較關鍵的演算法就是相似性的計算,有人與人之間的相似性計算,也有物品與物品之間的相似性計算。相似性計算函數要滿足如下特點:擁有同樣的函數簽名,以一個浮點數做為傳回值,其數值越大代表相似性越大。下面介紹幾個演算法:
a. 歐幾裡德距離(Euclidean Distance),我們知道兩個人的喜好越相似,他們的歐幾裡德距離值越小,所以需要將歐幾裡德距離轉化一下,這裡介紹一個簡單的轉化:1/(1 + dist), 這樣就能保證越相似取值越大,而且取值範圍在(0, 1]
b. 皮求遜相關係數(Pearson Correlation Coefficient), 取值範圍[-1, 1], 越相似值越大,滿足條件
c. Tanimoto系統 (Tanimoto Coefficient),最值範圍[0, 1], 越相似值越大,滿足條件
(3)在推薦系統裡,需要注意:
a. 沒有對某物品進行評價的人不能對該物品的推薦打分產生影響
b. 不能因為某人的偏執喜好(打很高或者很低的分)對推薦打分產生明顯的影響
為了避免上面的問題,通常採用加權平均的方法來計算某物品的推薦打分(詳見第三部分演算法實現)

3. 動手構建一個推薦系統

本部分通過構建一個真實的電影推薦系統,來介紹構建一個推薦的基本步驟與方法。

(1)資料集

本系統採用的資料是來自http://www.grouplens.org/node/73的資料,本次實驗採用的是如所示的第三份資料,總共有6040個使用者和3952部電影,以及1000209條相關評價。

(2)核心:推薦函數
typedef double (*ScoreFunc)(const double *, const double *, size_t); void GetRecommendation(const double ** allCritics,    //[in]  所有人的打分表size_t personNum,              //[in]  所有人的個數size_t size,                   //[in]  打分表大小size_t myIndex,                //[in]  我在打分表中下標ScoreFunc scorer,              //[in]  打分函數size_t recNum,                 //[out] 被推薦項個數int * recItems,                //[out] 被推薦項列表double * recScores             //[out] 被推薦項得分) {double * allRels = new double[personNum];::memset(allRels, 0, sizeof(double)*personNum);///計算所有的相關度for (size_t idx = 0; idx < personNum; ++ idx){if (idx == myIndex){continue; //it's me, just continue}allRels[idx] = scorer(allCritics[myIndex], allCritics[idx], size);} double * rels = new double[personNum];double * critics = new double[personNum];std::multimap mapScores;for (size_t itemIdx = 0; itemIdx < size; ++ itemIdx){::memset(rels, 0, sizeof(double)*personNum);::memset(critics, 0, sizeof(double)*personNum);///擷取有效相關度和對應的評分for (size_t personIdx = 0; personIdx < personNum; ++ personIdx){if (allCritics[personIdx][itemIdx] <= 0)//invalid score{rels[personIdx] = 0;critics[personIdx] = 0;}else{rels[personIdx] = allRels[personIdx];critics[personIdx] = allCritics[personIdx][itemIdx];}} ///計算加權打分double score = GetWeightedMead(critics, critics + personNum, rels, rels + personNum);mapScores.insert(std::make_pair(score, itemIdx));} ///擷取最終的推薦列表和對應的打分std::multimap::reverse_iterator oIt = mapScores.rbegin();for (size_t count = 0; count < recNum; ++ count) { recItems[count] = oIt->second;recScores[count] = oIt->first;++ oIt;} delete [] critics;delete [] rels;delete [] allRels;}
上面的函數,輸入所有人的評分表,以及需要提供推薦的人的相關資訊,輸出提供的推薦列表,以及相應的打分。這裡需要說明的一點是打分函數scorer, 它是一個ScoreFunc類型的函數指標,在實際調用的時候,可以通過傳入不同的打分函數,獲得在該打分函數下的推薦列表。需要注意打分函數的簽名在這裡必須與ScoreFunc的定義一致。下面是我定義的打分函數:
double GetEuclideanScore(double dist){return (1 / (1 + dist));} double GetPearsonScore(double coef){return coef;} double GetTanimotoScore(double coef){return coef;} double GetEuclideanScore(const double * myCritics, const double * hisCritics, size_t size){double dist = GetEuclideanDistance(myCritics, myCritics + size,hisCritics, hisCritics + size); return GetEuclideanScore(dist);} double GetPearsonScore(const double * myCritics, const double * hisCritics, size_t size){double coef = GetPearsonCorrelationCoefficient(myCritics, myCritics + size,hisCritics, hisCritics + size); return GetPearsonScore(coef);} double GetTanimotoScore(const double * myCritics, const double * hisCritics, size_t size){double coef = GetTanimotoCoefficient(myCritics, myCritics + size,hisCritics, hisCritics + size); return GetTanimotoScore(coef);}
上面的六個函數,前面三個是對結果進行正常化的函數,使結果滿足越相關越大。後面三個函數是真正的評價打分函數。在上面的實現中用到了GetEuclideanDistance, GetPearsonCorrelationCoefficient, GetTanimotoCoefficient, GetWeightedMead這四個函數,它們分別是計算歐幾裡德距離,Pearson相關係數,Tanimoto係數和加權平均值的函數,在這裡我就不給出具體的實現了。(3)實驗結果

我們用三種不同的打分函數,為第1000個使用者,推薦20部電影,來對比一下推薦的結果:
a. Euclidean結果:

b. Pearson結果:

c. Tanimoto結果:

從上面的結果中,可以得出如下結果:
a. 採用Euclidean打分推薦和採用Pearson打分推薦的結果中,有16個是相同的
b. 採用Pearson打分推薦和採用Tanimoto打分推薦的結果中,有15個是相同的
c. 採用Tanimoto打分推薦和採用Euclidean打分推薦的結果中,有16個是相同的
從上面的資料可以看出,雖說採用不同的打分函數進行推薦的結果存在一定的差異,但是整體上是一致的,不同的結果的相互覆蓋率都超過了75%, 這說明我們的打分函數都還是比較有效。

-

原創文章,轉載請註明出處:小武哥的部落格
本文固定連結:http://www.wuzesheng.com/?p=1277

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.