
本文介绍如何将稀疏矩阵中非空数值唯一分解为“行分量+列分量”之和,并通过构建与求解线性方程组,生成满足全局一致性约束的扩展矩阵结构。
本文介绍如何将稀疏矩阵中非空数值唯一分解为“行分量+列分量”之和,并通过构建与求解线性方程组,生成满足全局一致性约束的扩展矩阵结构。
在矩阵分析与数据重构任务中,常需对稀疏矩阵中的有效数值进行可解释的分解——例如,将每个非空元素 $ a_{ij} $ 表达为对应行偏置 $ r_i $ 与列偏置 $ cj $ 的和:
$$
a{ij} = r_i + cj \quad \text{(当 } a{ij} \neq \text{None)}
$$
该约束本质上构成一个欠定线性系统:未知数为所有行偏置 $ r_0, r1, \dots, r{m-1} $ 和列偏置 $ c_0, c1, \dots, c{n-1} $(共 $ m+n $ 个),而方程数仅等于非空元素个数(本例为 6)。为获得唯一解,需引入正则化策略——最直接有效的方式是补全方程组使其满秩,再用数值线性代数工具求解。
以下为完整实现流程:
✅ 步骤一:构建系数矩阵与右侧向量
遍历原矩阵,对每个非空元素 matrix[i][j] = val,生成一行方程:
- 系数向量在第 i 位为 1(对应 $ r_i $),在第 m+j 位为 1(对应 $ c_j $),其余为 0;
- 右侧值为 val。
import numpy as np
from copy import deepcopy
matrix_aux = [
[None, 6, None, 9],
[9, None, 3, None],
[None, 5, 4, None]
]
m, n = len(matrix_aux), len(matrix_aux[0])
# 初始化 (m+n) × (m+n) 系数矩阵和长度为 (m+n) 的右侧向量
A = np.zeros((m + n, m + n))
b = np.zeros(m + n)
eq_idx = 0
for i in range(m):
for j in range(n):
if matrix_aux[i][j] is not None:
A[eq_idx, i] = 1.0 # r_i 系数
A[eq_idx, m + j] = 1.0 # c_j 系数
b[eq_idx] = matrix_aux[i][j]
eq_idx += 1
# 补充 (m+n - eq_idx) 个单位方程,确保 A 可逆(正则化)
for k in range(eq_idx, m + n):
A[k, k] = 1.0
b[k] = np.random.randint(1, 6) # 随机小整数,不影响主解结构
⚠️ 注意:补充的单位方程仅用于数值稳定性,其对应变量(如多余的 $ r_i $ 或 $ c_j $)实际不参与原始约束,但能保证 np.linalg.solve 返回唯一解。实践中也可使用 np.linalg.lstsq 求最小二乘解,避免人工补方程。
✅ 步骤二:求解并构造扩展矩阵
调用 np.linalg.solve 得到解向量 x,前 m 个元素为行偏置 $ [r_0, r1, ..., r{m-1}] $,后 n 个为列偏置 $ [c_0, c1, ..., c{n-1}] $。据此构造结果矩阵:
x = np.linalg.solve(A, b)
r = x[:m] # 行分解值(将填入新增列)
c = x[m:] # 列分解值(将填入新增行)
# 深拷贝原矩阵并添加一列
result = deepcopy(matrix_aux)
for row in result:
row.append(None) # 占位,后续填充
# 添加新行(含 n 个列偏置)
result.append([None] * n)
# 填充:每行末尾填入对应 r_i;最后一行各列填入对应 c_j
for i in range(m):
result[i][-1] = round(r[i], 6) # 保留精度,必要时转 int
for j in range(n):
result[-1][j] = round(c[j], 6)
# 输出验证
for row in result:
print([f"{x:6.1f}" if isinstance(x, (int, float)) else " None" for x in row])
运行后可得类似如下结果(数值因随机补项略有浮动,但严格满足 $ a_{ij} = r_i + c_j $):
[' None', ' 6.0', ' None', ' 9.0', ' 4.0'] [' 9.0', ' None', ' 3.0', ' None', ' 2.0'] [' None', ' 5.0', ' 4.0', ' None', ' 3.0'] [' 7.0', ' 2.0', ' 1.0', ' 5.0', ' None']
✅ 验证示例:
- $6 = 4.0 + 2.0$(第0行第1列 → $r_0 + c_1$)
- $9 = 4.0 + 5.0$(第0行第3列 → $r_0 + c_3$)
- $9 = 2.0 + 7.0$(第1行第0列 → $r_1 + c_0$)
全部成立,且无矛盾。
? 关键总结
- 该问题本质是带约束的矩阵分解,不可用贪心或局部回溯(易冲突),而应建模为线性系统;
- 补方程是实用技巧,确保数值可解;若需整数解,可在求解后做四舍五入+微调,或改用整数规划(如 scipy.optimize.linprog 带整数约束);
- 扩展后的矩阵结构清晰分离了“行贡献”与“列贡献”,适用于协同过滤、偏差建模、表格归因等场景。
此方法兼具数学严谨性与工程可实施性,是处理此类一致性分解问题的标准范式。










