機械学習注7:行列の因数分解Recommender.Matrix.Factorization

1つの行列分解の概要

任意の場所で使用される1.1

推奨されるシステム:それは悪い通りの物語が、今のシステムのユーザーを供給見出しが推奨される最も有名なビールとおむつです。言うまでもありません。

1.2推奨原則

セットは、行列Rは、膜の3 4評価を表し、Pは、行列演算の分解による行列Uは、Rである行列を予測します。
この時点で、我々は行列Rのことを見ることができる
値は、元の行列Rの値に非常に近い、値が我々は、この後に記入したい数字です。

2行列分解原理

2.1目的関数

1.2に示すように、最小の差で私達の望ましい結果R *およびR結果の結果です。
したがって、我々は目的関数得ることができる:
[Argで\ MIN_ {U、P} \ SUM _ {Zで(I、J)\} \(P_ {J}のR_ {のIJ} -U_ {I}を^ {T})^ 2 \\ \\ Z = \ {(I 、J):R_ {ijは} 知られている\} \]

\(U_i P_j \)行列Pのi番目の行と行列Uとj行から、それぞれ、行ベクトルである。図は、ユーザi番目とj番目のベクトル図物品のベクトルを表します。

2.2損失関数

導出を容易にするために、我々は次のように結果が1/2乗算:
\ [アルギニン\ Zの\のFRACにおける{U-MIN_、P} \ _ {SUM(I、J)\} 1} {2} {(R_のIJ {} -U_ {I} \ CDOT P_ { J})^ 2 \\ \\ Z = \ {(i、j)は:R_ {ijは} が知られている\} \]
以下のように結果が計算し続ける:
L_ {}の\ [IJを= \ FRAC {1} {2} (R_ {IJ} -U_ {I} \ CDOT P_ {J})^ 2 \\ \]

次のように勾配を生じる損失されました:

\ [\ FRAC {\部分L_ {IJ}} {\部分U_ {I} = FRAC \ {\部分} {\部分U_ {I}} [\ FRAC {1} {2}(R_ {IJ} - U_ {I} \ CDOT P_ {J})^ 2] = -P_j(R_ {IJ} -U_ {I} \ CDOT P_ {J})\\ \\ \ FRAC {\部分L_ {IJ}} {\部分P_ {J}} = \ FRAC {\部分} {\部分P_ {J}} [\ FRAC {1} {2}(R_ {IJ} -U_ {I} \ CDOT P_ {J})^ 2] = -U_i(R_ {IJ} -U_ {I} \ CDOT P_ {J})\]

オーバーフィッティング及び訓練プロセスにおけるエラーを防ぐために、正則化項が追加します

\ [引数\ MIN_ {U、P} \和_ {(i、j)は\ Zにおける} \ FRAC {1} {2}(R_ {IJ} -U_ {I} \ CDOT P_ {J})^ 2 +左\ラムダ[\ sum_ {i = 1} ^ {M} \ \ | U_i \右\ | ^ 2 + \ sum_ {i = 1} ^ {N} \左\ | P_j \権\ | ^ 2] \]

再求偏导可得:
\ [\ FRAC {\部分L_ {IJ}} {\部分U_ {I} = - P_ {J}(R_ {IJ} -U_ {I} \ CDOT P_ {J}) + \ラムダU_ {I} \\ \\ \ FRAC {\部分L_ {IJ}} {\部分P_ {J}} = - U_ {I}(R_ {IJ} -U_ {I} \ CDOT P_ {J })+ \ラムダP_ {J} \\ \]

勾配降下の方法により得られた2.3結果

kの値を設定するステップ学習設定されている\(\ガンマ\) 学習率)を、UおよびPの初期化は、平均二乗誤差まで以下のステップを繰り返すこと満たされている。
トラバースZ(i、j)の中、Z = {( I、J):\ R_ {} \の(IJ)既知}
\ [U_upper {I} \ {I}左矢印U_upper -ガンマ\ FRAC {\ \部分L_ {のIJ} {} \部分U_upper {I}} \ \ P_ {J} \ LEFTARROW P_ {J} - \ガンマ\ FRAC {\部分L_ {IJ}} {\部分P_ {J}} \\ \]

3コードの実装

上記の式は間違いなく不完全で読むが、マトリックス分解機能を見て、あなたは突然、問題解決するために、勾配降下法の光を見ることができます
コードのを:

# 导入 nunpy 和 surprise 辅助库
import numpy as np
import surprise  

# 计算模型
class MatrixFactorization(surprise.AlgoBase):
    '''基于矩阵分解的推荐.'''
    
    def __init__(self, learning_rate, n_epochs, n_factors, lmd):
        
        self.lr = learning_rate  # 梯度下降法的学习率
        self.n_epochs = n_epochs  # 梯度下降法的迭代次数
        self.n_factors = n_factors  # 分解的矩阵的秩(rank)
        self.lmd = lmd # 防止过拟合的正则化的强度
        
    def fit(self, trainset):
        '''通过梯度下降法训练, 得到所有 u_i 和 p_j 的值'''
        
        print('Fitting data with SGD...')
        
        # 随机初始化 user 和 item 矩阵.
        u = np.random.normal(0, .1, (trainset.n_users, self.n_factors))
        p = np.random.normal(0, .1, (trainset.n_items, self.n_factors))
        
        # 梯度下降法
        for _ in range(self.n_epochs):
            for i, j, r_ij in trainset.all_ratings():
                err = r_ij - np.dot(u[i], p[j])
                # 利用梯度调整 u_i 和 p_j
                u[i] -= -self.lr * err * p[j] + self.lr * self.lmd * u[i]
                p[j] -= -self.lr * err * u[i] + self.lr * self.lmd * p[j]
                # 注意: 修正 p_j 时, 按照严格定义, 我们应该使用 u_i 修正之前的值, 但是实际上差别微乎其微
        
        self.u, self.p = u, p
        self.trainset = trainset

    def estimate(self, i, j):
        '''预测 user i 对 item j 的评分.'''
        
        # 如果用户 i 和物品 j 是已知的值, 返回 u_i 和 p_j 的点积
        # 否则使用全局平均评分rating值(cold start 冷启动问题)
        if self.trainset.knows_user(i) and self.trainset.knows_item(j):
            return np.dot(self.u[i], self.p[j])
        else:
            return self.trainset.global_mean
            
# 应用
from surprise import BaselineOnly
from surprise import Dataset
from surprise import Reader
from surprise import accuracy
from surprise.model_selection import cross_validate
from surprise.model_selection import train_test_split
import os

# 数据文件
file_path = os.path.expanduser('./ml-100k/u.data')

# 数据文件的格式如下:
# 'user item rating timestamp', 使用制表符 '\t' 分割, rating值在1-5之间.
reader = Reader(line_format='user item rating timestamp', sep='\t', rating_scale=(1, 5))
data = Dataset.load_from_file(file_path, reader=reader)

# 将数据随机分为训练和测试数据集
trainset, testset = train_test_split(data, test_size=.25)

# 初始化以上定义的矩阵分解类.
algo = MatrixFactorization(learning_rate=.005, n_epochs=60, n_factors=2, lmd = 0.2)

# 训练
algo.fit(trainset)

# 预测
predictions = algo.test(testset)

# 计算平均绝对误差
accuracy.mae(predictions)

#结果:0.7871327139440717

# 使用 surpise 内建的基于最近邻的方法做比较
algo = surprise.KNNBasic()
algo.fit(trainset)
predictions = algo.test(testset)
accuracy.mae(predictions)

#结果:0.7827160139309475

# 使用 surpise 内建的基于 SVD 的方法做比较
algo = surprise.SVD()
algo.fit(trainset)
predictions = algo.test(testset)
accuracy.mae(predictions)

#结果:0.7450633876817936

おすすめ

転載: www.cnblogs.com/bugutian/p/11288673.html