pythonは物品に基づく協同フィルタリング(ItemCF)映画推薦アルゴリズムを実現する

23338 ワード

最近、メンタープロジェクトの必要性のため、数日かけて項亮の「推薦システム実践」を学び、pythonで本のItem Collabortive Filtering、すなわち物品に基づく協同フィルタリングアルゴリズムを実現した.
共同フィルタリングとは
協同フィルタリングは推薦システムの中で最も経典とよく使われるアルゴリズムであり、その核心思想はその名前である:すべてのユーザーの歴史行為データを利用して、ユーザーは絶えずウェブサイトとインタラクティブになることを通じて、推薦リストにユーザーの興味のないものを絶えず濾過することができて、それによってますます需要を満たすことができる.
共同フィルタリングは、次の2つに分類されます.
  • ユーザーの共同フィルタリング(UserCF):ターゲットユーザーに推薦する場合は、まず彼と似たような他のユーザーを見つけて、それらのユーザーが好きなプロジェクトからターゲットユーザーが見たことがないプロジェクトを見つけて彼に推薦します.
  • プロジェクトの共同フィルタリング(ItemCF):ターゲットユーザ履歴ビューリストに類似する他のプロジェクトを見つけて、これらの類似項目をソートし、最後の推奨リストを生成します.

  • 採点予測ですか、それともTopNがお勧めですか.
    採点予測とTopN推奨は推奨システムの2つの予測精度を測定する指標であり、多くの推奨研究は採点予測に基づいて展開されている.主にこの方面の早期研究に従事する組織GroupLensが主に映画の採点に対して行われているためであり、Netflixなどの推奨アルゴリズムの大会も主に採点予測問題を解決しているが、採点が高いのは良い推奨なのか.もちろんそうではありません.ユーザーが良いスコアを与えたのは、彼が最も見たいか、購入したいという意味ではありません.
    部分コード実装
  • はデータセットを記載し、トレーニングセットとテストセット
  • を区分する.
        def get_dataset(self, filename, pivot=0.75):
    
            trainSet_len = 0
            testSet_len = 0
            for line in self.load_file(filename):
                user, movie, rating, timestamp = line.split(',')
                if(random.random() < pivot):
                    self.trainSet.setdefault(user, {})
                    self.trainSet[user][movie] = rating
                    trainSet_len += 1
                else:
                    self.testSet.setdefault(user, {})
                    self.testSet[user][movie] = rating
                    testSet_len += 1
            print('           !')
            print('     = %s' % trainSet_len)
            print('     = %s' % testSet_len)
    

    ここでpivot(ピボット)因子はデータセットを3:1でトレーニングセットとデータセットに分けた.
  • 映画間の類似度を計算し、類似行列
  • を生成する.
        def calc_movie_sim(self):
            #  movies_popular  
            for user, movies in self.trainSet.items():
                for movie in movies:
                #  movie  movies_popular   ,           0+1,   movie_popular       ,           
                    if movie not in self.movie_popular:
                        self.movie_popular[movie] = 0
                    else:
                        self.movie_popular[movie] += 1
            self.movie_count = len(self.movie_popular)
            print("         = %d" % self.movie_count)
        
            for user, movies in self.trainSet.items():
                for m1 in movies:
                    for m2 in movies:
                        if m1 == m2:
                            continue
                        #        :                           1,               ,  +1
                        self.movie_sim_matrix.setdefault(m1, {})
                        self.movie_sim_matrix[m1].setdefault(m2, 0)
                        self.movie_sim_matrix[m1][m2] += 1    
            print("           !")
            # print("         movieId=1    :")
            # print(self.movie_sim_matrix['1'])  
    
            #           
            for m1, related_movies in self.movie_sim_matrix.items():
                for m2, count in related_movies.items():
                    #   00
                    if self.movie_popular[m1] == 0 or self.movie_popular[m2] == 0:
                        self.movie_sim_matrix[m1][m2] = 0
                    else:
                        self.movie_sim_matrix[m1][m2] = count / math.sqrt(self.movie_popular[m1] * self.movie_popular[m2])
            print('           !')
           # print("       movieId=736   :")
           # print(self.movie_sim_matrix['736'])  
    
  • 推奨リスト
  • を生成する.
    def recommend(self, user):
            K = int(self.n_sim_movie)
            N = int(self.n_rec_movie)
            rank = {}
            watched_movies = self.trainSet[user]
            for movie, rating in watched_movies.items():
                #             ,                     KK           ,     rank   ,   movieid ,  (    ) w(        ) rating(            )   
                for related_movie, w in sorted(self.movie_sim_matrix[movie].items(), key=itemgetter(1), reverse=True)[:K]:
                    if related_movie in watched_movies:
                        continue
                    rank.setdefault(related_movie, 0)
                    #     
                    rank[related_movie] += w * float(rating)
            return sorted(rank.items(), key=itemgetter(1), reverse=True)[:N]
    
    

    4.評価アルゴリズム
        def evaluate(self):
            N = int(self.n_rec_movie)
            reuserN = input("            :(     457)")
            reuserN = int(reuserN)
            #        
            hit = 0
            rec_count = 0
            test_count = 0
            #    
            all_rec_movies = set()
            for user,m in list(self.trainSet.items())[:reuserN]:
                test_moives = self.testSet.get(user, {})
                rec_movies = self.recommend(user)
                print("   %s         :" % user)
                self.precommend(rec_movies)
                #  ,   w   recommend w    ,   w               ,         rank      
                for movie, w in rec_movies:
                    if movie in test_moives:
                        hit += 1
                    all_rec_movies.add(movie)
                rec_count += N
                test_count += len(test_moives)
    
            precision = hit / (1.0 * rec_count)
            recall = hit / (1.0 * test_count)
            coverage = len(all_rec_movies) / (1.0 * self.movie_count)
            print('   =%.4f\t   =%.4f\t   =%.4f' % (precision, recall, coverage))
    

    最後に、ItemCFデータセットと完全なコードアドレスを添付します.