基于内在非负性的矩阵分解模型(INLF)

今天写的是2018年发表在IEEE transactions上的一篇关于矩阵分解的论文。文章链接如下:

一种非负性矩阵分解模型(INLF)

先上文章的思维导图,除了模型的数学推导部分,其余的重点都囊括在内了。

1、该文章的主要创新点是引入一个sigmoid函数,使得矩阵分解出来的两个因子模型中的所有值全为非负的。那sigmoid函数的优势在哪呢?

一、值域在[0,1]之间,这就满足了元素值的非负性特点;

二、sigmoid函数成S形状,较为平滑,并且导数是大于0的。所以在使用梯度下降更新元素值的时候,不容易出现局部最优代替全局最优的情况。

三、较传统的梯度下降和非负乘法更新等模型相比,INLF模型既有传统模型的计算速度快、易存储等优点,同时又能兼容大多数一般性的优化方法。

四、引入sigmoid函数的INLF模型,能够使得分解出来的因子矩阵的值大体服从正态分布,数据波动较小,有利于实验。

五、引入sigmoid函数的INLF模型在大规模数据缺失值预测场景中,预测准确率高,收敛速度快,RSME(均方根误差)和MAE(平均绝对误差)指标小。故在工业场景中可大量应用。

2、简要说一下模型

主体思想还是针对原始矩阵中的值和预测的值作残差平方和,然后记为损失函数,通过最小化损失函数,完成优化;

不同的是引入一个sigmoid函数,实现非负性,并对带有sigmoid的损失函数做优化,得到第一次的因子矩阵,之后对因子矩阵

做第二次sigmoid变换,得到最终的因子矩阵。

   1)、初始损失函数:

  

2)、引入sigmoid函数后的损失函数:(其中\Phi函数为sigmoid函数)

3)、引入正则化项防止过拟合:

4)、梯度下降

5)、求导,因子矩阵中值的更新公式

其中,\Phi (x)求导为\Phi (x)求导为\Phi (x)\left (1-\Phi (x) \right ),\eta为学习率,\lambda为正则化系数。

 

3、该文章作者的论证逻辑严谨,是值得学习一下的。为了凸显INLF模型的优越性,在实验比较部分,共进行了三方面的输出。

     首先,实验说明INLF模型本身效果好,因子矩阵分布大体为高斯分布,数据波动小;模型RMSE和MAE较小,且收敛速度快。

   其次,与一些线性发非负矩阵分解模型,像如WNLF、PNLF、ANLF等做实验比较,证明了INLF在各方面指标上性能突出。

  再者,与非线性模型Kernel 非负矩阵分解模型做实验比较,突出INLF性能的优越性。

  这种横向、纵向多方面的实验结果比对的逻辑是非常值得学习的。

4、最后,上代码、实验。

import numpy as np
import matplotlib.pyplot as plt
import time


#sigmoid函数
def sigmoidFunc(x):
    return 1/(1+np.exp(-x))


#实现INLF内在非负性矩阵分解
#参数分别是原始矩阵,行数,列数,因子矩阵的维度,迭代次数,学习率1,学习率2
def inlfFun(ma,m,n,d,count,a1,a2):
    
    #初始化两个因子矩阵(0-0.05范围内)
    A=np.random.uniform(0,0.05,[m,d])#基矩阵
    B=np.random.uniform(0,0.05,[n,d])#系数矩阵
    
    #列表记录每一次迭代过后的损失值
    resultLoss=[0]
    
    #记录模型消耗的时间
    time_start=time.time()
    
    #标记变量,记录迭代次数
    ii=0
    print("开始训练")
    #算法具体实现
    while ii<count:
        for row in range(m):
            for column in range(n):
                if ma[row,column]>0:#只拟合大于0的数
                    Rmn=0#预测值
                    rmn=ma[row,column]#原始值
                    
                    #临时变量,记录sigmoid变换
                    ak=0
                    bk=0
                    
                    for k in range(d):
                        ak=sigmoidFunc(A[row,k])
                        bk=sigmoidFunc(B[column,k])
                        #向量点乘得到预测值
                        Rmn+=ak*bk
                    
                    #标记预测值与真实值之间的误差值
                    ERRmn=rmn-Rmn
                    
                    #梯度下降更新LF特征因子
                    for k in range(d):                        
                        A[row,k]=A[row,k]+a1*ak*(1-ak)*(bk*ERRmn-a2*ak)
                        B[column,k]=B[column,k]+a1*bk*(1-bk)*(ak*ERRmn-a2*bk)
        
        ii+=1#更新迭代次数

        #计算每次迭代完成后的损失值,添加到列表用于作图分析
        e=0
        for i in range(len(ma)):
            for j in range(len(ma[i])):
                if ma[i,j]>0:
                    e+=pow(ma[i,j]-(np.dot(A[i,:],B[j,:])),2)
        resultLoss.append(e)
    
    #将因子再经过一次sigmoid变化,得到最后的因子LF矩阵
    for row in range(m):
        for k in range(d):
            A[row,k]=sigmoidFunc(A[row,k])
    for column in range(n):
        for k in range(d):
            B[column,k]=sigmoidFunc(B[column,k])
    
    time_end=time.time()
    #算法消耗的总时间
    total_time=time_end-time_start
    print("总共耗时:",total_time)
    return list(resultLoss)


#作图分析
def matplotAnalys(resultLoss):#参数为损失值列表
    x=range(len(resultLoss))
    plt.plot(x,resultLoss,color='r',linewidth=3)
    plt.title("Convergence Curve")
    plt.xlabel("iterations")
    plt.ylabel("Loss value")
    plt.show()
    

#计算最小损失值及其迭代次数
def getMinLoss(resultLoss):
    min=10000
    minIndex=0
    for i in range(1,len(resultLoss)):
        if resultLoss[i]<min:
            min=resultLoss[i]
            minIndex=i
    return (min,minIndex)

if __name__=="__main__":
#     inlfFun(ma,m,n,d,count,a1,a2)
    #矩阵行列
    m=20
    n=15
    #初始矩阵
    ma=np.random.randint(0,6,size=(m,n))
    #因子矩阵维度
    d=8
    #迭代次数
    count=3000
    #学习率
    a1=0.005
    a2=0.005
    #跑算法模型
    resultLoss=inlfFun(ma,m,n,d,count,a1,a2)
    #计算最小损失值
    min,minIndex=getMinLoss(resultLoss)
    print("最小损失值是:",min)
    print("最优迭代次数数是:",minIndex)
    #做图分析
    matplotAnalys(resultLoss)

                   

这个损失值看着是比较大的,因为损失值是误差的平方累加和,所以初始矩阵越大,损失值就越大。

其次,因为sigmoid函数最后得到的值都在(0,1)之间,可能会使得数据在真实场景中失去一定的代表意义,也是损失值较大的原因,如果能对sigmoid函数得到的数据做一些数据处理,损失值会降低很多。

其实,针对INLF矩阵分解模型,最好用RMSE和MAE两个评价指标,因为误差值更小,更能反应效果。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值