现给出例子:

矩阵降为二维怎么算 python 矩阵怎么降阶举例_矩阵

矩阵降为二维怎么算 python 矩阵怎么降阶举例_迭代_02

矩阵降为二维怎么算 python 矩阵怎么降阶举例_迭代_03

矩阵降为二维怎么算 python 矩阵怎么降阶举例_矩阵降为二维怎么算 python_04

矩阵降为二维怎么算 python 矩阵怎么降阶举例_损失函数_05

8

3

-

2

矩阵降为二维怎么算 python 矩阵怎么降阶举例_矩阵_06

9

-

-

5

矩阵降为二维怎么算 python 矩阵怎么降阶举例_线性代数_07

7

-

-

8

矩阵降为二维怎么算 python 矩阵怎么降阶举例_损失函数_08

-

1

6

9

假设

矩阵降为二维怎么算 python 矩阵怎么降阶举例_矩阵_09

代表用户代号

矩阵降为二维怎么算 python 矩阵怎么降阶举例_损失函数_10

代表商品编号,而表格中的的数值则为用户对商品的评分,“ - ”代表未对其评分。现要求预测出用户对商品未评价的分数是多少?这里就需要用到矩阵分解对其进行预测,我们可将上述表格看作一个矩阵对其求解。

一、矩阵分解原理

矩阵分解原理很简单,例如有一矩阵R,求两个矩阵P、Q,使P、Q的矩阵乘法等于R,

矩阵降为二维怎么算 python 矩阵怎么降阶举例_矩阵降为二维怎么算 python_11

这里P、Q称为R的分解矩阵,我们可通过预测R的分解矩阵来预测R,而预测方式需要用到梯度下降。

二、梯度下降进行矩阵分解

(1)公式讲解

建立损失函数

矩阵降为二维怎么算 python 矩阵怎么降阶举例_矩阵_12

 同时为了防止过拟合我们需要对损失函数加上正则化函数

矩阵降为二维怎么算 python 矩阵怎么降阶举例_损失函数_13

PS:关于过拟合的概念和解决方式可以移步这位大佬的文章,很容易理解

其中R为初始矩阵,P、Q为其分解矩阵,m、n为R的长和宽、b为正则系数

为了能够用代码实现需要对矩阵的每一元素依次求解,需要对损失函数作进一步改进可得: 

    

矩阵降为二维怎么算 python 矩阵怎么降阶举例_损失函数_14

矩阵降为二维怎么算 python 矩阵怎么降阶举例_损失函数_15

 

                                                   

矩阵降为二维怎么算 python 矩阵怎么降阶举例_迭代_16

 

                                                   

矩阵降为二维怎么算 python 矩阵怎么降阶举例_线性代数_17

矩阵降为二维怎么算 python 矩阵怎么降阶举例_矩阵_18

其中

矩阵降为二维怎么算 python 矩阵怎么降阶举例_矩阵_19

代表R的第i行第j列的元素的损失函数

矩阵降为二维怎么算 python 矩阵怎么降阶举例_矩阵_20

代表R的第i行第j列的元素,

矩阵降为二维怎么算 python 矩阵怎么降阶举例_迭代_21

同理,n既为P的宽又为Q的长。

损失函数的求导

关于p的求导

矩阵降为二维怎么算 python 矩阵怎么降阶举例_损失函数_22

关于q的求导:

矩阵降为二维怎么算 python 矩阵怎么降阶举例_矩阵降为二维怎么算 python_23

更新P矩阵与Q矩阵

矩阵降为二维怎么算 python 矩阵怎么降阶举例_矩阵_24

矩阵降为二维怎么算 python 矩阵怎么降阶举例_迭代_25

其中lr为迭代系数,即学习率

检测损失函数是否小于设定误差值

矩阵降为二维怎么算 python 矩阵怎么降阶举例_迭代_26

则停止迭代,

矩阵降为二维怎么算 python 矩阵怎么降阶举例_矩阵_27

为提前的设定允许误差范围。

反正继续重复执行上述步骤。

三、代码实现(python)

(1)必要的库的导入以及一些参数的设置

创建矩阵时未评分的用0代替

import numpy as np
import matplotlib.pyplot as plt

lr = 0.05               #学习率
e=0.01                       #误差值
b=0.005                   #正则系数
maxloop=15000            #最大迭代次数
k = 2                #分解矩阵阶数
#创建初始矩阵,0代表未评分
score=np.array([[8,3,0,2],
               [9,0,0,5],
               [7,0,0,8],
               [0,1,6,9]])
#作图数据收集用的列表
D_Loss = [] 
V_Loss = []

(2)矩阵分解(MF 函数)

def MF(R, k):  #矩阵分解

创建随机R的俩个分解矩阵以及它们的偏导矩阵

#创建分解矩阵
P = np.random.rand(R.shape[0], k)
Q = np.random.rand(k, R.shape[1])
#k为提前设定的矩阵阶数,k既等于P的宽又等于Q的长,这样才能P、Q才能满足矩阵乘法
#偏导矩阵
dP = np.zeros((R.shape[0], k))
dQ = np.zeros((k, R.shape[1]))

求偏导以及更新P,Q

for m in range(maxloop):
    count += 1
    D_Value_Sum = 0

    #求偏导矩阵
    for i in range(R.shape[0]):
        for j in range(R.shape[1]):
            D_Value = R[i, j] - np.dot(P[i, :], Q[:, j])
            D_Value_Sum += abs(D_Value)
            if R[i, j] > 0:
                for k in range(P.shape[1]):
                    dP[i,k] = -2 * Q[k,j] * D_Value + b * P[i,k] #损失函数关于P的偏导
                    dQ[k,j] = -2 * P[i,k] * D_Value + b * Q[k,j] #损失函数关于Q的偏导
                for k in range(P.shape[1]):
                    P[i, k] = P[i, k] - lr * dP[i, k]  # 更新P
                    Q[k, j] = Q[k, j] - lr * dQ[k, j]  # 更新Q

③误差值的判断

D_Value_Sum = D_Value_Sum /(R.shape[0] * R.shape[1])#损失函数的值的求解

#作图时的数据收集
D_Value_Loss = pow(D_Value_Sum,2)
D_Loss.append(D_Value_Sum)
V_Loss.append(D_Value_Loss)

if m % 1000 == 0: print(D_Value_Sum)#每迭代1000次输出误差值

if D_Value_Sum < e: break#迭代条件判断

return P,Q,count

(3)结果输出以及作图

P,Q,count= MF(score,k)
print("P=\n",P)
print()
print("Q=\n",Q)
print("score=\n",np.dot(P,Q))
print("共迭代{}次".format(count))
#创建画布
plt.figure()
# 想用中文必须进行设置RC参数
plt.rcParams['font.sans-serif'] = 'SimHei'
# 设置RC参数字体,让其支持中文
plt.rcParams['axes.unicode_minus'] = False
plt.subplot(1,2,1)
plt.plot(D_Loss,color="red")
plt.xlabel("迭代次数")
plt.ylabel("误差值")
plt.title("误差值变化曲线")

plt.subplot(1,2,2)
plt.plot(V_Loss,color="blue")
plt.xlabel("迭代次数")
plt.ylabel("误差值")
plt.title("损失函数变化曲线")

plt.show()

(4)运行结果展示

P=
 [[2.41059748 0.57011407]
 [2.17149241 1.59128246]
 [0.88111496 2.65739805]
 [0.13628212 3.02581629]]

Q=
 [[2.92288979 1.17734687 0.1111894  0.12739064]
 [1.66424432 0.27737902 1.97788322 2.96891167]]
score=
 [[7.99471986 2.99624707 1.39565193 1.99970585]
 [8.99531581 2.99798816 3.38881781 5.00100486]
 [6.99796153 1.7744844  5.35399365 8.00182587]
 [5.43403521 0.99974928 5.9998644  9.00074238]]
共迭代15000次

 误差值变化

矩阵降为二维怎么算 python 矩阵怎么降阶举例_线性代数_28

 四、完整代码

import numpy as np
import matplotlib.pyplot as plt

lr = 0.05               #学习率
e=0.01                       #误差值
b=0.005                   #正则系数
maxloop=15000            #最大迭代次数
k = 2                #分解矩阵阶数
#创建初始矩阵,0代表未评分
score=np.array([[8,3,0,2],
               [9,0,0,5],
               [7,0,0,8],
               [0,1,6,9]])
#作图数据收集用的列表
D_Loss = []
V_Loss = []
def MF(R, k):  #矩阵分解
    #创建两个分解矩阵
    P = np.random.rand(R.shape[0], k)
    Q = np.random.rand(k, R.shape[1])
    #偏导矩阵
    dP = np.zeros((R.shape[0], k))
    dQ = np.zeros((k, R.shape[1]))
    #开始模拟
    count = 0
    for m in range(maxloop):
        count += 1
        D_Value_Sum = 0

        #求偏导矩阵
        for i in range(R.shape[0]):
            for j in range(R.shape[1]):
                D_Value = R[i, j] - np.dot(P[i, :], Q[:, j])
                D_Value_Sum += abs(D_Value)
                if R[i, j] > 0:#若评分不等于0则
                    for k in range(P.shape[1]):
                        dP[i,k] = -2 * Q[k,j] * D_Value + b * P[i,k] #损失函数关于P的偏导
                        dQ[k,j] = -2 * P[i,k] * D_Value + b * Q[k,j] #损失函数关于Q的偏导
                    for k in range(P.shape[1]):
                        P[i, k] = P[i, k] - lr * dP[i, k]  # 更新P
                        Q[k, j] = Q[k, j] - lr * dQ[k, j]  # 更新Q
        D_Value_Sum = D_Value_Sum /(R.shape[0] * R.shape[1])#损失函数的值的求解
        #作图时的数据收集
        D_Value_Loss = pow(D_Value_Sum,2)
        D_Loss.append(D_Value_Sum)
        V_Loss.append(D_Value_Loss)
        if m % 1000 == 0: print(D_Value_Sum)#每迭代1000次输出误差值

        if D_Value_Sum < e: break

    return P,Q,count

P,Q,count= MF(score,k)
print("P=\n",P)
print()
print("Q=\n",Q)
print("score=\n",np.dot(P,Q))
print("共迭代{}次".format(count))
#创建画布
plt.figure()
# 想用中文必须进行设置RC参数
plt.rcParams['font.sans-serif'] = 'SimHei'
# 设置RC参数字体,让其支持中文
plt.rcParams['axes.unicode_minus'] = False
plt.subplot(1,2,1)
plt.plot(D_Loss,color="red")
plt.xlabel("迭代次数")
plt.ylabel("误差值")
plt.title("误差值变化曲线")

plt.subplot(1,2,2)
plt.plot(V_Loss,color="blue")
plt.xlabel("迭代次数")
plt.ylabel("误差值")
plt.title("损失函数变化曲线")

plt.show()