• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 224  文章 - 41  trackbacks - 0
            <2008年11月>
            2627282930311
            2345678
            9101112131415
            16171819202122
            23242526272829
            30123456

            享受編程

            常用鏈接

            留言簿(11)

            隨筆分類(159)

            隨筆檔案(224)

            文章分類(2)

            文章檔案(4)

            經(jīng)典c++博客

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

                     
                   Slope One 之一 : 簡單高效的協(xié)同過濾算法(轉(zhuǎn))(
                  原文地址:http://blog.sina.com.cn/s/blog_4d9a06000100am1d.html

                   現(xiàn)在做的一個項目中需要用到推薦算法, 在網(wǎng)上查了一下. Beyond Search介紹了一個協(xié)同過濾算法(Collaborative Filtering) : Slope One;和其它類似算法相比, 它的最大優(yōu)點在于算法很簡單, 易于實現(xiàn), 執(zhí)行效率高, 同時推薦的準(zhǔn)確性相對很高;
                 
            基本概念
                   Slope One的基本概念很簡單, 例子1, 用戶X, Y和A都對Item1打了分. 同時用戶X,Y還對Item2打了分, 用戶A對Item2可能會打多少分呢?
            User Rating to Item 1 Rating to Item 2
            X 5 3
            Y 4 3
            A 4 ?


                    根據(jù)SlopeOne算法, 應(yīng)該是:4 - ((5-3) + (4-3))/2 = 2.5.
                    解釋一下. 用戶X對Item1的rating是5, 對Item2的rating是3, 那么他可能認(rèn)為Item2應(yīng)該比Item1少兩分. 同時用戶Y認(rèn)為Item2應(yīng)該比Item1少1分. 據(jù)此我們知道所有對Item1和Item2都打了分的用戶認(rèn)為Item2會比Item1平均少1.5分. 所以我們有理由推薦用戶A可能會對Item2打(4-1.5)=2.5分;

                    很簡單是不是? 找到對Item1和Item2都打過分的用戶, 算出rating差的平均值, 這樣我們就能推測出對Item1打過分的用戶A對Item2的可能Rating, 并據(jù)此向A用戶推薦新項目.
                    這里我們能看出Slope One算法的一個很大的優(yōu)點, 在只有很少的數(shù)據(jù)時候也能得到一個相對準(zhǔn)確的推薦, 這一點可以解決Cold Start的問題.

                   加權(quán)算法
                   接下來我們看看加權(quán)算法(Weighted Slope One). 如果有100個用戶對Item1和Item2都打過分, 有1000個用戶對Item3和Item2也打過分. 顯然這兩個rating差的權(quán)重是不一樣的. 因此我們的計算方法是
                  (100*(Rating 1 to 2) + 1000(Rating 3 to 2)) / (100 + 1000)。更詳細的加權(quán)算法實例:請看這里

                   上面討論的是用戶只對項目的喜好程度打分.還有一種情況下用戶也可以對項目的厭惡程度打分. 這時可以使用雙極SlopeOne算法(BI-Polar SlopeOne). 我還在研究這篇論文,搞懂了再寫吧, 呵呵;

                   
                    Slope One 算法是由 Daniel Lemire 教授在 2005 年提出. 這里可以找到論文原文(PDF);上面也列出了幾個參考實現(xiàn). 現(xiàn)在有Python, Java和Erlang, 還沒有C#.這篇: tutorial about how to implement Slope One in Python是一個很好的怎么實現(xiàn)SlopeOne并使用它來推薦的例子。

                  Slope One 算法 (三) :加權(quán)平均實例
            原文地址:http://blog.sina.com.cn/s/blog_4d9a06000100am69.html

            1. 例子:
            2.  
            3. 首先計算item1和item2的平均差值,((5-3)+(3-4))/2=0.5,還有item1和item3的平均差值,就是5-2=3,然后推算lucy對item1的評分,根據(jù)item1和item2的平均差值來看lucy對item1的評分可能為2+0.5=2.5,同理根據(jù)item1和item3的平均差值lucy對item1的評分可能為5+3=8.
            4. 現(xiàn)在如何取舍那?使用加權(quán)平均數(shù)應(yīng)該是一種比較好的方法:(因為2.5是根據(jù)兩個值推算的,8是通過一個只推算的)
            5. slope one 算法差不多真的就是這么簡單了!
            6. 有一個開源的Java程序taste里面有一個完整的slope one算法的實現(xiàn),包括程序和一個關(guān)于grouplens數(shù)據(jù)的實例程序(或者說是驗證程序……)。
            7. 個人覺得slope one 很好、很強大呀!足夠簡單,推薦準(zhǔn)確度也不遜色與其他復(fù)雜的推薦算法(當(dāng)然,這個東西更大程度上取決與數(shù)據(jù)樣本)。而且taste程序?qū)懙囊埠懿诲e,稍加改造應(yīng)該就可以用了。


             Slope One 之二: C#實現(xiàn) 
                    原文地址:http://blog.sina.com.cn/s/blog_4d9a06000100am69.html

                    
            上一篇簡單介紹了Slope One算法的概念, 這次介紹C#實現(xiàn)
            使用基于Slope One算法的推薦需要以下數(shù)據(jù):
            1. 有一組用戶
            2. 有一組Items(文章, 商品等)
            3. 用戶會對其中某些項目打分(Rating)表達他們的喜好
            Slope One算法要解決的問題是, 對某個用戶, 已知道他對其中一些Item的Rating了, 向他推薦一些他還沒有Rating的Items, 以增加銷售機會. :-)

            一個推薦系統(tǒng)的實現(xiàn)包括以下三步:
            1. 計算出任意兩個Item之間Rating的差值
            2. 輸入某個用戶的Rating記錄, 推算出對其它Items的可能Rating值
            3. 根據(jù)Rating的值排序, 給出Top Items;

            第一步:例如我們有三個用戶和4個Items, 用戶打分的情況如下表.
            Ratings User1 User2 User3
            Item1 5 4 4
            Item2 4 5 4
            Item3 4 3 N/A
            Item4 N/A 5 5

            在第一步中我們的工作就是計算出Item之間兩兩的打分之差, 也就是使說計算出以下矩陣:
              Item1 Item2 Item3 Item4
            Item1 N/A 0/3 2/2 -2/2
            Item2 0/3 N/A 2/2 -1/2
            Item3 -2/2 -2/2 N/A -2/1
            Item4 2/2 1/2 2/1 N/A


            考慮到加權(quán)算法, 還要記錄有多少人對這兩項打了分(Freq), 我們先定義一個結(jié)構(gòu)來保存Rating:
                public class Rating
                {
                    public float Value { get; set; }
                    public int Freq { get; set; }

                    public float AverageValue
                    {
                        get {return Value / Freq;}
                    }
                }
            我決定用一個Dictionary來保存這個結(jié)果矩陣:
                public class RatingDifferenceCollection : Dictionary<string, Rating>
                {
                    private string GetKey(int Item1Id, int Item2Id)
                    {
                        return Item1Id + "/" + Item2Id;
                    }

                    public bool Contains(int Item1Id, int Item2Id)
                    {
                        return this.Keys.Contains<string>(GetKey(Item1Id, Item2Id));
                    }

                    public Rating this[int Item1Id, int Item2Id]
                    {
                        get {
                                return this[this.GetKey(Item1Id, Item2Id)];
                        }
                        set { this[this.GetKey(Item1Id, Item2Id)] = value; }
                    }
                }

            接下來我們來實現(xiàn)SlopeOne類. 首先創(chuàng)建一個RatingDifferenceCollection來保存矩陣, 還要創(chuàng)建HashSet來保持系統(tǒng)中總共有哪些Items:
                public class SlopeOne
                     
                    public RatingDifferenceCollection _DiffMarix = new RatingDifferenceCollection();  // The dictionary to keep the diff matrix
                    public HashSet<int> _Items = new HashSet<int>();  // Tracking how many items totally

            方法AddUserRatings接收一個用戶的打分記錄(Item-Rating): public void AddUserRatings(IDictionary<int, float> userRatings)
            AddUserRatings中有兩重循環(huán), 外層循環(huán)遍歷輸入中的所有Item, 內(nèi)層循環(huán)再遍歷一次, 計算出一對Item之間Rating的差存入_DiffMarix, 記得Freq加1, 以記錄我們又碰到這一對Items一次:
                Rating ratingDiff = _DiffMarix[item1Id, item2Id];
                ratingDiff.Value += item1Rating - item2Rating;
                ratingDiff.Freq += 1;

            對每個用戶調(diào)用AddUserRatings后, 建立起矩陣. 但我們的矩陣是以表的形式保存:
              Rating Dif Freq
            Item1-2 0 3
            Item1-3 1 2
            Item2-1 0 3
            Item2-3 1 2
            Item3-1 -1 2
            Item3-2 -1 2
            Item1-4 -1 2
            Item2-4 -0.5 2
            Item3-4 -2 1
            Item4-1 1 2
            Item4-2 0.5 2
            Item4-3 2 1



            第二步:輸入某個用戶的Rating記錄, 推算出對其它Items的可能Rating值:
            public IDictionary<int, float> Predict(IDictionary<int, float> userRatings)
            也是兩重循環(huán), 外層循環(huán)遍歷_Items中所有的Items; 內(nèi)層遍歷userRatings, 用此用戶的ratings結(jié)合第一步得到的矩陣, 推算此用戶對系統(tǒng)中每個項目的Rating:
                Rating itemRating = new Rating(); // Prediction of this user's rating
                ...
                Rating diff = _DiffMarix[itemId, inputItemId]:
                itemRating.Value += diff.Freq * (diff.AverageValue + userRating.Value);
                itemRating.Freq += diff.Freq;

            第三步:得到用戶的Rating預(yù)測后,就可以按rating排序, 向用戶推薦了. 測試一下:
                Dictionary<int, float> userRating userRating = new Dictionary<int, float>();
                userRating.Add(1, 5);
                userRating.Add(3, 4);
                IDictionary<int, float> Predictions = test.Predict(userRating);
                foreach (var rating in Predictions)
                {
                    Console.WriteLine("Item " + rating.Key + " Rating: " + rating.Value);
                 
            輸出:
            Item 2 Rating: 5
            Item 4 Rating: 6

            改進:
            觀察之前產(chǎn)生的矩陣可以發(fā)現(xiàn), 其中有很多浪費的空間; 例如: 對角線上永遠是不會有值的. 因為我們是用線性表保存矩陣值, 已經(jīng)避免了這個問題;
            對角線下方的值和對角線上方的值非常對稱,下方的值等于上方的值乘以-1; 在數(shù)據(jù)量很大的時候是很大的浪費. 我們可以通過修改RatingDifferenceCollection來完善. 可以修改GetKey方法, 用Item Pair來作為Key:
                private string GetKey(int Item1Id, int Item2Id) {
                    return (Item1Id < Item2Id) ? Item1Id + "/" + Item2Id : Item2Id + "/" + Item1Id ;;
                }
            完整代碼在這里,在.net 3.5上調(diào)試通過;

             

             
            Reference:
            Tutorial about how to implement Slope One 
            in Python
            Slope One Predictors 
            for Online Rating-Based Collaborative Filtering
            Recommender Systems: Slope One


            using System;
            using System.Collections.Generic;
            using System.Linq;
            using System.Text;

            namespace SlopeOne
            {
                
            public class Rating
                
            {
                    
            public float Value getset; }
                    
            public int Freq getset; }

                    
            public float AverageValue
                    
            {
                        
            get return Value / Freq; }
                    }

                }


                
            public class RatingDifferenceCollection : Dictionary<string, Rating>
                
            {
                    
            private string GetKey(int Item1Id, int Item2Id)
                    
            {
                        
            return (Item1Id < Item2Id) ? Item1Id + "/" + Item2Id : Item2Id + "/" + Item1Id ;
                    }


                    
            public bool Contains(int Item1Id, int Item2Id)
                    
            {
                        
            return this.Keys.Contains<string>(GetKey(Item1Id, Item2Id));
                    }


                    
            public Rating this[int Item1Id, int Item2Id]
                    
            {
                        
            get {
                                
            return this[this.GetKey(Item1Id, Item2Id)];
                        }

                        
            set this[this.GetKey(Item1Id, Item2Id)] = value; }
                    }

                }


                 
            public class SlopeOne
                
            {       
                    
            public RatingDifferenceCollection _DiffMarix = new RatingDifferenceCollection();  // The dictionary to keep the diff matrix
                    public HashSet<int> _Items = new HashSet<int>();  // Tracking how many items totally

                    
            public void AddUserRatings(IDictionary<intfloat> userRatings)
                    
            {
                        
            foreach (var item1 in userRatings)
                        
            {
                            
            int item1Id = item1.Key;
                            
            float item1Rating = item1.Value;
                            _Items.Add(item1.Key);

                            
            foreach (var item2 in userRatings)
                            
            {
                                
            if (item2.Key <= item1Id) continue// Eliminate redundancy
                                int item2Id = item2.Key;
                                
            float item2Rating = item2.Value;

                                Rating ratingDiff;
                                
            if (_DiffMarix.Contains(item1Id, item2Id))
                                
            {
                                    ratingDiff 
            = _DiffMarix[item1Id, item2Id];
                                }

                                
            else
                                
            {
                                    ratingDiff 
            = new Rating();
                                    _DiffMarix[item1Id, item2Id] 
            = ratingDiff;
                                }


                                ratingDiff.Value 
            += item1Rating - item2Rating;
                                ratingDiff.Freq 
            += 1;
                            }

                        }

                    }


                    
            // Input ratings of all users
                    public void AddUerRatings(IList<IDictionary<intfloat>> Ratings)
                    
            {
                        
            foreach(var userRatings in Ratings)
                        
            {
                            AddUserRatings(userRatings);
                        }

                    }


                    
            public IDictionary<intfloat> Predict(IDictionary<intfloat> userRatings)
                    
            {
                        Dictionary
            <intfloat> Predictions = new Dictionary<intfloat>();
                        
            foreach (var itemId in this._Items)
                        
            {
                            
            if (userRatings.Keys.Contains(itemId))    continue// User has rated this item, just skip it

                            Rating itemRating 
            = new Rating();

                            
            foreach (var userRating in userRatings)
                            
            {
                                
            if (userRating.Key == itemId) continue;
                                
            int inputItemId = userRating.Key;
                                
            if (_DiffMarix.Contains(itemId, inputItemId))
                                
            {
                                    Rating diff 
            = _DiffMarix[itemId, inputItemId];
                                    itemRating.Value 
            += diff.Freq * (userRating.Value + diff.AverageValue * ((itemId < inputItemId) ? 1 : -1));
                                    itemRating.Freq 
            += diff.Freq;
                                }

                            }

                            Predictions.Add(itemId, itemRating.AverageValue);               
                        }

                        
            return Predictions;
                    }


                    
            public static void Test()
                    
            {
                        SlopeOne test 
            = new SlopeOne();

                        Dictionary
            <intfloat> userRating = new Dictionary<intfloat>();
                        userRating.Add(
            15);
                        userRating.Add(
            24);
                        userRating.Add(
            34);
                        test.AddUserRatings(userRating);

                        userRating 
            = new Dictionary<intfloat>();
                        userRating.Add(
            14);
                        userRating.Add(
            25);
                        userRating.Add(
            33);
                        userRating.Add(
            45);
                        test.AddUserRatings(userRating);

                        userRating 
            = new Dictionary<intfloat>();
                        userRating.Add(
            14);
                        userRating.Add(
            24);
                        userRating.Add(
            45);
                        test.AddUserRatings(userRating);

                        userRating 
            = new Dictionary<intfloat>();
                        userRating.Add(
            15);
                        userRating.Add(
            34);

                        IDictionary
            <intfloat> Predictions = test.Predict(userRating);
                        
            foreach (var rating in Predictions)
                        
            {
                            Console.WriteLine(
            "Item " + rating.Key + " Rating: " + rating.Value);
                        }

                    }

                }

            }

             可惜啊,代碼是vs2008寫的,我的項目是vs2005的,改編了一下這里可以下載!
            posted on 2010-07-19 17:49 漂漂 閱讀(10295) 評論(0)  編輯 收藏 引用 所屬分類: 算法
            国产精品永久久久久久久久久| 国产69精品久久久久9999APGF| 久久精品卫校国产小美女| 欧美午夜精品久久久久久浪潮| 久久久无码精品亚洲日韩软件| 国内精品久久久久久久涩爱| 精品国产一区二区三区久久| 久久国产精品-国产精品| 亚洲国产二区三区久久| 久久久WWW成人| 久久久国产精华液| 久久99九九国产免费看小说| 亚洲午夜福利精品久久| 亚洲国产美女精品久久久久∴| 精品久久人妻av中文字幕| 情人伊人久久综合亚洲| 一本久久a久久精品综合夜夜| 久久99久久无码毛片一区二区| 亚洲?V乱码久久精品蜜桃| 色欲综合久久中文字幕网| 久久久青草青青亚洲国产免观| 久久亚洲中文字幕精品一区四| 狠狠综合久久AV一区二区三区| 久久美女人爽女人爽| 波多野结衣AV无码久久一区| 91精品国产9l久久久久| 伊人久久成人成综合网222| 国产精品9999久久久久| 伊人 久久 精品| 精品久久久久久无码中文字幕一区| 久久精品这里只有精99品| 99久久超碰中文字幕伊人| 要久久爱在线免费观看| 亚洲欧美日韩精品久久| 久久久久se色偷偷亚洲精品av| 精品一久久香蕉国产线看播放| 亚洲成色WWW久久网站| 蜜桃麻豆www久久国产精品| 国产精品久久久久久一区二区三区| 欧美久久久久久| 久久免费精品视频|