python实现矩阵补全和奇异值软阈值算法改进模型

这段代码实现了一个低秩矩阵补全 (Low-Rank Matrix Completion, LRMC) 算法,专门用于填补稀疏矩阵(缺失值矩阵)中的空缺条目。例如,协同过滤推荐系统、图像修复或任何需要从观测数据中恢复缺失数据模式的场景。使用RSE指标可以评估算法预测缺失值的性能。我就不过多描述,有问题可以私信我。

import numpy as np
import pandas as pd

def LRMC(sparse_mat, dense_mat, alpha, rho, maxiter):
    pos_train = np.where(sparse_mat != 0)
    pos_test = np.where((sparse_mat == 0) & (dense_mat != 0))
    binary_mat = sparse_mat.copy()
    binary_mat[pos_train] = 1
    print("pos_test", pos_test)

    X = sparse_mat.copy()
    Z = np.zeros(sparse_mat.shape)
    T = np.zeros(sparse_mat.shape)
    rse = np.zeros(maxiter)

    for it in range(maxiter):
        u, s, v = np.linalg.svd(X + T / rho, full_matrices=False)
        vec = s - alpha / rho
        vec[np.where(vec < 0)] = 0
        Z = np.matmul(np.matmul(u, np.diag(vec)), v)
        X = Z - T / rho
        X[pos_train] = sparse_mat[pos_train]
        T = T - rho * (Z - X)
        rse[it] = (np.linalg.norm(X[pos_test] - dense_mat[pos_test], 2)
                   / np.linalg.norm(dense_mat[pos_test], 2))
        print(f"Iteration {it + 1}: rse = {rse[it]}")
    return X, rse


def RM(missing_rate, dense_mat):
    dim = dense_mat.shape
    sparse_tensor = dense_mat * np.round(np.random.rand(*dim) + 0.5 - missing_rate)
    return sparse_tensor


# 示例用法
dense_mat = pd.read_csv('sz_speed.csv', header=None).values  # 假设原始矩阵是一个随机矩阵
missing_rate = 0.2
sparse_mat = RM(missing_rate, dense_mat)
alpha = 0.1
rho = 0.005
maxiter = 200
mat_hat, rse_lr = LRMC(sparse_mat, dense_mat, alpha, rho, maxiter)

# 打印MAE结果
print("X", mat_hat)
print("Final MAE for completed values:", rse_lr[-1])
result_df = pd.DataFrame(mat_hat)

result_df.to_csv('result_matrix.csv', index=False)

print("Result matrix saved to result_matrix.csv")

改进后的模型如下(主要是加入L正则项):

新代码实现了一种使用交替方向乘子法 (ADMM) 的矩阵补全方法,与之前的低秩矩阵补全 (LRMC) 方法有一些区别。在LRMC中,只用SVD进行奇异值的软阈值化。在ADMM中,同样有奇异值处理,但是它将矩阵补全问题分为多个子问题。此外ADMM算法引入了图的邻接矩阵 A 和由此生成的拉普拉斯矩阵 L(利用图结构信息进行约束),这在处理如图结构数据时,例如社交网络数据,可以通过反映节点之间的关系来辅助补全任务。

# 随机缺失的处理
 def RM(self, missing_rate, dense_mat):
     dim = dense_mat.shape
     sparse_tensor = dense_mat * np.round(np.random.rand(*dim) + 0.5 - missing_rate)
     return sparse_tensor
def admm_matrix_completion(self, dense_mat, A, gamma, lambd, maxiter, missing_rate, epsilon=1e-6):
        """
        ADMM矩阵补全算法
        """
        sparse_mat = self.RM(missing_rate, dense_mat)
        pos_train = np.where(sparse_mat != 0)
        pos_test = np.where((sparse_mat == 0) & (dense_mat != 0))
        X = sparse_mat.copy()
        Z = np.zeros(sparse_mat.shape)
        W = np.zeros(sparse_mat.shape)
        rse = np.zeros(maxiter)
        # 拉普拉斯矩阵(L=D-A)
        L = np.diag(A.sum(axis=0)) - A
        

首先调用随机缺失处理方法 RM 生成一个稀疏矩阵 sparse_mat,其中一些元素根据 missing_rate 被随机置为零。

其中pos_train: 稀疏矩阵中非零元素的索引,用于训练。
      pos_test: 稀疏矩阵中为零且稠密矩阵中非零元素的索引,用于测试,计算重构误差。

然后初始化变量,X为当前估计的矩阵,最初设置为稀疏矩阵。Z为中间变量,W为拉格朗日乘子。rse用于记录每次迭代的相对重构误差。L = np.diag(A.sum(axis=0)) - A是为了创建拉普拉斯矩阵 L,其中 D 是度矩阵,A 是邻接矩阵,L = D - A。

        for it in range(maxiter):
            # X更新公式
            X = self.singular_value_thresholding(Z, W, 1 / lambd)
            X[pos_train] = sparse_mat[pos_train]

            # Z更新公式
            # Z =(γL.T*L+λI)-1 * (λX+W) + Y   (对应文中的公式)
            inv_term = np.linalg.inv(gamma * np.dot(L.T, L) + lambd * 
            np.identity(L.shape[0]))
            Z_Omega_c = np.dot(inv_term, lambd * X + W)
            Z_Omega = sparse_mat
            Z = self.l1_projection(Z_Omega + Z_Omega_c, epsilon)

            # W更新公式
            W = W + lambd * (X - Z)
            rse[it] = (np.linalg.norm(X[pos_test] - dense_mat[pos_test], 2)
                       / np.linalg.norm(dense_mat[pos_test], 2))
            print(f"Iteration {it + 1}: rse = {rse[it]}")
        return X, rse

主迭代循环使用奇异值阈值法对 Z 和 W 进行处理以更新 X,并且保留稀疏矩阵中训练位置的原始值。然后计算更新公式中涉及的逆矩阵更新 Z,通过将当前估计的矩阵 (X 和 W) 输入到 L1 投影中来进行稀疏性约束。接着更新拉格朗日乘子 W 用于调整 Z 的变化。并且加入计算记录当前迭代的相对重构误差(rse),用于监控算法收敛情况。最后返回补全后的矩阵 X 和每次迭代的重构误差 rse。

    def l1_projection(self, Z, epsilon):
        Z[Z < -epsilon] += epsilon
        Z[Z > epsilon] -= epsilon
        Z[(Z >= -epsilon) & (Z <= epsilon)] = 0
        return Z

l1_projection函数实现了L1正则化

    def singular_value_thresholding(self, Z, W, lambd):
        """
        奇异值阈值处理函数
        """
        # 对矩阵 Z - W / lambd 进行奇异值分解(SVD)
        U, S, VT = svd(Z - W / lambd, full_matrices=False)
        # 将奇异值进行软阈值处理,将小于 lambd / 2 的奇异值置零。
        S_thresh = np.maximum(S - lambd / 2, 0)
        # 用处理后的奇异值重新构建矩阵
        return U @ np.diag(S_thresh) @ VT

singular_value_thresholding函数实现了奇异值阈值法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值