機器學習之推薦算法


1、知識點

"""
推薦系統
    1、相似度計算:
        1、歐幾里德距離
        2、皮爾遜相關系數
        3、Cosin距離
        
    2、推薦相似度選擇:
            1、固定數量的鄰居
            2、基於相似度門檻的鄰居
            
    3、基於用戶的協同過濾:根據用戶和其他用戶之間的相關系數值,選擇值越小的用戶數據,並和該用戶比較,推薦物品
            需要解決的問題:1、已知用戶評分矩陣R(一般很稀疏) 2、推斷矩陣中空格empty cells處的值
        基於用戶的協同過濾不利於對全0矩陣進行推薦,其解決方案:
            1、相似度計算最好使用皮爾遜相似度
            2、考慮共同打分物品的數目
            3、對打分進行歸一化處理
            4、設置一個相似度閾值  
        缺點:1、稀疏問題(很多值為0)   2、大用戶量不利於計算,因此不推薦基於用戶的協同過濾
        row:為用戶  ,column:為物品
        場景:實時新聞、突發情況(實時數據)


    4、基於物品的協同過濾:根據物品和物品之間的相似度,然后取閾值,獲取相鄰的值,即推薦物品   (一般使用皮爾遜相關系數)
        優點:1、計算性能高,用戶數量大於物品數量
        row:為用戶物品  ,column:為用戶
        場景:圖書、電子商務、電影(離線數據)
        
    5、用戶冷啟動問題(即用戶注冊的時候):
            1、引導用戶把自己的一些屬性表達出來
            2、利用現有的開發數據平台
            3、根據用戶注冊的屬性
            4、推薦排序榜單
      
    6、物品冷啟動問題:
        1、文本分析
        2、主題模型
        3、打標簽
        4、推薦排行榜單   
          
    7、隱語義模型:將矩陣進行分解,然后求解隱含特征F,從而可以根據F得到一個先的具有填充值的NM矩陣,從而實現推薦,即NM = NF * FM
            1、從數據出發,今天個性化推薦
            2、用戶和物品之間有着隱含聯系
            3、隱含因子讓計算機能理解就好
            4、將用戶和物品通過中介隱含因子聯系起來
        隱語義模型參數選擇:
            1、隱特征的個數F,通常F=100
            2、學習率alpha 別太大
            3、正則化參數lambda,別太大
            4、負樣本和正樣本比例ratio    
    8、協同過濾與  隱語義對比
        1、原理:協同過濾基於統計方法,隱語義基於建模
        2、空間復雜度,隱語義模型較小
        3、實時推薦依舊難,目前離線計算多
      
    9、模型評估指標
        1、准確率 :均方誤差
        2、召回率 :正負樣本中,推薦正樣本中正確的比例
        3、覆蓋率
        4、多樣性
        
推薦難點:
    1、計算量解決
    2、模型的好壞怎么評估,怎么更新
  • L1正則化可以產生稀疏權值矩陣,即產生一個稀疏模型,可以用於特征選擇
  • L2正則化可以防止模型過擬合(overfitting);一定程度上,L1也可以防止過擬合

suprise 推薦系統api
    url:https://surprise.readthedocs.io/en/stable/getting_started.html
    數據地址:http://files.grouplens.org/datasets/movielens/ml-100k-README.txt

基於用戶的協同過濾:
"""

2、代碼實現推薦案例

# coding = utf-8
from __future__ import (absolute_import,division,print_function,unicode_literals)

from surprise import SVD,KNNBasic
from surprise import Dataset
from  surprise import evaluate,print_perf

from surprise import GridSearch

import pandas as pd


import os
import io
from surprise import KNNBaseline

def collaborativeFiltering():
    """
    協同過濾算法
    :return:
    """
    #1、加載數據
    data = Dataset.load_builtin('ml-100k')
    data.split(n_folds=3)#3折,結果有3個

    #2、實例化協同過濾算法對象
    algo = KNNBasic()
    pref =evaluate(algo,data,measures=['RMSE','MAE'])#算法模型評估
    print_perf(pref)

def matrixFactorization():
    """
    SVD,矩陣分解
    :return:
    """
    param_grid = {'n_epochs':[5,10],'lr_all':[0.002,0.005],'reg_all':[0.4,0.6]}
    grid_search = GridSearch(SVD,param_grid,measures=['RMSE','FCP'])
    data = Dataset.load_builtin('ml-100k')
    data.split(n_folds=3)  # 3折,結果有3個
    grid_search.evaluate(data)

    print(grid_search.best_score['RMSE']) #最好的得分值
    print(grid_search.best_params['RMSE'])  # 最好的得分值

    result_df =pd.DataFrame.from_dict(grid_search.cv_results)
    print(result_df)

def recommendItem():
    data = Dataset.load_builtin('ml-100k') #加載u.data文件
    trainset = data.build_full_trainset()
    sim_options = {'name':'pearson_baseline','user_based':False} #皮爾遜相似度pearson_baseline ,'user_based':False表示基於物品的協同過濾
    algo = KNNBaseline(sim_options=sim_options) #協同過濾
    algo.train(trainset) #訓練

    #獲取電影的id
    rid_to_name,name_to_rid = read_item_names()
    toy_story_raw_id = name_to_rid['Now and Then (1995)']
    print(toy_story_raw_id) #數據文件中的id

    toy_story_inner_id =algo.trainset.to_inner_iid(toy_story_raw_id)
    print(toy_story_inner_id)#實際計算矩陣中的id

    toy_story_neighbors_id = algo.get_neighbors(toy_story_inner_id,k=10)
    print(toy_story_neighbors_id) #實際計算矩陣中的id

    toy_story_neighbors_id = (algo.trainset.to_raw_iid(inner_id) for inner_id in toy_story_neighbors_id) #數據文件中的id

    toy_story_neighbors_name = (rid_to_name[rid] for rid in toy_story_neighbors_id) #數據文件中的name

    print("##########推薦item#########")
    for movie in toy_story_neighbors_name:
        print(movie)


def read_item_names():
    file_name=('./ml-100k/u.item')
    rid_to_name={}
    name_to_rid={}

    with io.open(file_name,'r',encoding='ISO-8859-1') as  f:
        for line in f:
            line = line.split('|')
            rid_to_name[line[0]] = line[1]
            name_to_rid[line[1]]=line[0]
    return rid_to_name,name_to_rid

if __name__ == '__main__':
    recommendItem()

 3、基於物品的協同過濾圖

 

4、代碼案例2

import recsys.algorithm
recsys.algorithm.VERBOSE = True


from recsys.algorithm.factorize import SVD
from recsys.datamodel.data import Data
from recsys.evaluation.prediction import RMSE
import os,sys

tmpfile = "/tmp/movielens.zip"
moviefile = "./ml-1m/movies.dat"

class RecommendSystem(object):

    def __init__(self, filename, sep, **format):
        self.filename = filename
        self.sep = sep
        self.format = format

        # 訓練參數
        self.k = 100
        self.min_values = 10
        self.post_normalize = True

        self.svd = SVD()

        # 判斷是否加載
        self.is_load = False

        # 添加數據處理
        self.data = Data()

        # 添加模型評估
        self.rmse = RMSE()

    def get_data(self):
        """
        獲取數據
        :return: None
        """
        # 如果模型不存在
        if not os.path.exists(tmpfile):
            # 如果數據文件不存在
            if not os.path.exists(self.filename):
                sys.exit()
            # self.svd.load_data(filename=self.filename, sep=self.sep, format=self.format)
            # 使用Data()來獲取數據
            self.data.load(self.filename, sep=self.sep, format=self.format)
            train, test = self.data.split_train_test(percent=80)
            return train, test
        else:
            self.svd.load_model(tmpfile)
            self.is_load = True
            return None, None


 def train(self, train):
        """
        訓練模型
        :param train: 訓練數據
        :return: None
        """
        if not self.is_load:
            self.svd.set_data(train)
            self.svd.compute(k=self.k, min_values=self.min_values, post_normalize=self.post_normalize, savefile=tmpfile[:-4])
        return None

    def rs_predict(self, itemid, userid):
        """
        評分預測
        :param itemid: 電影id
        :param userid: 用戶id
        :return: None
        """
        score = self.svd.predict(itemid, userid)
        print "推薦的分數為:%f" % score
        return score


 def recommend_to_user(self, userid):
        """
        推薦給用戶
        :param userid: 用戶id
        :return: None
        """
        recommend_list = self.svd.recommend(userid, is_row=False)

        # 讀取文件里的電影名稱
        movie_list = []

        for line in open(moviefile, "r"):
            movie_list.append(' '.join(line.split("::")[1:2]))

        # 推薦具體電影名字和分數
        for itemid, rate in recommend_list:
            print  ("給您推薦了%s,我們預測分數為%s" %(movie_list[itemid],rate))
        return None


 def evaluation(self, test):
        """
        模型的評估
        :param test: 測試集
        :return: None
        """
        # 如果模型不是直接加載
        if not self.is_load:

            # 循環取出測試集里面的元組數據<評分,電影,用戶>
            for value, itemid, userid in test.get():
                try:
                    predict = self.rs_predict(itemid, userid)
                    self.rmse.add(value, predict)
                except KeyError:
                    continue
            # 計算返回誤差(均方誤差)
            error = self.rmse.compute()

            print  ("模型誤差為%s:" % error)

        return None


if __name__ == "__main__":
    rs = RecommendSystem("./ml-1m/ratings.dat", "::", row=1, col=0, value=2, ids=int)
    train, test = rs.get_data()
    rs.train(train)
    rs.evaluation(test)
    # rs.rs_predict(1,1)
    rs.recommend_to_user(1)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM