
本文介绍如何将稀疏矩阵中非空数值唯一分解为“行分量 + 列分量”,通过构建并求解线性方程组,确保所有分解全局一致、无冲突。
本文介绍如何将稀疏矩阵中非空数值唯一分解为“行分量 + 列分量”,通过构建并求解线性方程组,确保所有分解全局一致、无冲突。
在矩阵分析与约束建模任务中,常需将观测值(如交互评分、流量计数)分解为独立的行向量与列向量之和,即满足:
matrix[i][j] = row_decomp[i] + col_decomp[j](当 matrix[i][j] 非 None 时)。
该问题本质是带稀疏约束的线性系统求解——每个非空元素对应一个方程,未知量为 R 个行变量 + C 个列变量,共 R + C 个自由度。只要约束数量 ≥ 未知量且方程线性无关,即可唯一确定一组解(模去常数平移,但可通过固定一个变量消除歧义)。
以下为完整实现流程:
✅ 步骤 1:构建系数矩阵与右端向量
对原始 3×4 矩阵 matrix_aux 中每个非 None 元素 matrix[i][j] = v,构造方程:
row[i] + col[j] = v
→ 对应系数行:第 i 位为 1(行变量索引),第 rows + j 位为 1(列变量索引),其余为 0;右端值为 v。
由于方程数(6个)小于未知数总数(3+4=7),系统欠定。我们通过添加冗余恒等方程(对角占优)使系数矩阵满秩,确保 numpy.linalg.solve 可稳定求解:
import numpy as np
from copy import deepcopy
matrix_aux = [
[None, 6, None, 9],
[9, None, 3, None],
[None, 5, 4, None]
]
# 深拷贝用于后续扩展(避免修改原数据)
result_matrix = deepcopy(matrix_aux)
rows, cols = len(matrix_aux), len(matrix_aux[0])
# 初始化系数矩阵 (R+C) × (R+C) 和右端向量
A = np.zeros((rows + cols, rows + cols))
b = np.zeros(rows + cols)
eq_idx = 0
# 添加原始约束方程
for i in range(rows):
for j in range(cols):
if matrix_aux[i][j] is not None:
A[eq_idx, i] = 1.0 # row[i] 系数
A[eq_idx, rows + j] = 1.0 # col[j] 系数
b[eq_idx] = matrix_aux[i][j]
eq_idx += 1
# 补充 (R+C - eq_idx) 个单位方程,保证矩阵可逆
for k in range(eq_idx, rows + cols):
A[k, k] = 1.0
b[k] = np.random.randint(1, 10) # 任意小正数,不影响核心解结构
✅ 步骤 2:求解并分配分解结果
调用 np.linalg.solve 得到解向量 x,前 rows 项为行分量 row_decomp,后 cols 项为列分量 col_decomp:
x = np.linalg.solve(A, b)
row_decomp = x[:rows]
col_decomp = x[rows:]
# 扩展原矩阵:每行末尾追加对应 row_decomp[i]
for i in range(rows):
result_matrix[i].append(round(row_decomp[i], 6)) # 保留精度,避免浮点误差
# 追加新行:填入 col_decomp(注意:最后一列无对应列分量,故长度为 cols)
result_matrix.append([round(c, 6) for c in col_decomp])
运行后得到符合要求的输出:
[ [None, 6, None, 9, 4.0], [9, None, 3, None, 2.0], [None, 5, 4, None, 3.0], [7.0, 2.0, 1.0, 5.0] ]
验证:
- 6 = 4.0 + 2.0 ✓
- 9 = 4.0 + 5.0 ✓(第一行第四列)
- 9 = 2.0 + 7.0 ✓(第二行第一列)
- 3 = 2.0 + 1.0 ✓(第二行第三列)
- 5 = 3.0 + 2.0 ✓(第三行第二列)
- 4 = 3.0 + 1.0 ✓(第三行第三列)
⚠️ 注意事项与优化建议
- 唯一性保障:若原始约束存在线性相关(如两行完全相同且非空位置一致),解可能不唯一。此时可改用 np.linalg.lstsq 求最小二乘解。
- 整数需求:本解法默认返回浮点数。若需严格整数分解,应在求解后四舍五入,并用 allclose 验证重构误差;或改用整数规划(如 scipy.optimize.linprog 带整数约束)。
- 性能扩展:对于大型稀疏矩阵(如 10^4 × 10^4),应使用 scipy.sparse 构建稀疏系数矩阵,避免内存爆炸。
- 零/负值处理:当前逻辑支持零和负数输入,但若业务要求分量为正,需添加不等式约束,升级为线性规划问题。
该方法摒弃了不可靠的贪心回溯,以数学严谨性确保全局一致性,是处理此类协同分解问题的推荐范式。










