scipy调用lil_matrix.diagonal()触发sparse matrix length is ambiguous错误
问题描述
计算lil_matrix格式稀疏矩阵指定对角线元素和时抛出类型错误,复现代码如下:
sm1 = np.sum(board.diagonal(k=i1-row1)) sm2 = np.sum(board.diagonal(k=i2-row2))
抛出的错误信息:
TypeError: sparse matrix length is ambiguous; use getnnz() or shape[0]
已知信息:
type(board)返回值为<class 'scipy.sparse._lil.lil_matrix'>,参数row1, row2, i1, i2均为整数- 执行
print(np.sum(board.diagonal(k=i1-row1)))时,程序会先打印正确计算结果,之后才抛出上述类型错误 - 经排查
diagonal方法内部实现为return self.tocsr().diagonal(k=k),直接调用board.tocsr()会抛出完全相同的错误
完整错误日志:
Traceback (most recent call last): File "/usr/lib/python3.8/code.py", line 90, in runcode exec(code, self.locals) File "<input>", line 1, in <module> File "/snap/pycharm-professional/285/plugins/python/helpers/pydev/_pydev_bundle/pydev_umd.py", line 198, in runfile pydev_imports.execfile(filename, global_vars, local_vars) # execute the script File "/snap/pycharm-professional/285/plugins/python/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile exec(compile(contents+"\n", file, 'exec'), glob, loc) File "/home/noah/PycharmProjects/nQueens/sa_sparse.py", line 94, in <module> y.run() File "/home/noah/PycharmProjects/nQueens/sa_sparse.py", line 63, in run self.swap(newSol) File "/home/noah/PycharmProjects/nQueens/sa_sparse.py", line 34, in swap newCost = self.calcFastCost(board.board, row1, row2) File "/home/noah/PycharmProjects/nQueens/sa_sparse.py", line 47, in calcFastCost sm1 = np.sum(board.diagonal(k=i1-row1)) File "/home/noah/nQueens/lib/python3.8/site-packages/scipy/sparse/_base.py", line 1214, in diagonal return self.tocsr().diagonal(k=k) File "/home/noah/nQueens/lib/python3.8/site-packages/scipy/sparse/_lil.py", line 459, in tocsr _csparsetools.lil_get_lengths(self.rows, indptr[1:]) File "_csparsetools.pyx", line 111, in scipy.sparse._csparsetools.lil_get_lengths File "_csparsetools.pyx", line 117, in scipy.sparse._csparsetools._lil_get_lengths_int32 File "/home/noah/nQueens/lib/python3.8/site-packages/scipy/sparse/_base.py", line 345, in __len__ raise TypeError("sparse matrix length is ambiguous; use getnnz()" TypeError: sparse matrix length is ambiguous; use getnnz() or shape[0]
故障原因
核心问题是当前lil_matrix实例的内部rows属性被污染:lil_matrix的rows属性本应是长度等于矩阵行数的嵌套列表,每个子列表存储对应行非零元素的列索引,tocsr()转换时C扩展会遍历每个子列表调用len()统计每行非零元素个数。
从错误栈可以判断,代码在之前的矩阵修改操作(比如皇后位置交换逻辑)中,错误地将一个稀疏矩阵对象赋值给了rows属性下的某个子列表位置,导致C扩展遍历到该位置时,对稀疏矩阵对象调用len(),触发了稀疏矩阵禁止直接取长度的类型错误。
先打印正确结果再报错的反常现象,是因为对角线提取操作在tocsr()流程的前半段已经完成并返回,后续遍历统计行长度的步骤触发异常时,求和、打印逻辑已经执行完毕。
解决方案
- 先定位污染位置,在调用对角线计算代码前增加校验逻辑,快速定位被错误赋值的行:
# 校验rows属性合法性 for row_idx, row_content in enumerate(board.rows): if not isinstance(row_content, list): print(f"第{row_idx}行rows数据类型异常,当前类型:{type(row_content)}") break - 修正矩阵修改逻辑的赋值错误:操作
lil_matrix元素时,不要直接修改内部rows属性,使用标准的board[row, col] = value接口赋值,避免将非整数、非列表类型的值写入rows结构。 - 临时规避方案(仅临时绕过,不能解决根本问题):提前将矩阵转为CSR格式缓存,避免每次取对角线都触发
tocsr()转换:
注意该方案无法修复board_csr = board.tocsr() sm1 = np.sum(board_csr.diagonal(k=i1-row1)) sm2 = np.sum(board_csr.diagonal(k=i2-row2))rows属性污染问题,后续其他稀疏矩阵操作仍可能触发同类错误,必须修正赋值逻辑才能彻底解决。
内容的提问来源于stack exchange,提问作者Brot
相关产品推荐
相关产品推荐

