用scipy.sparse而非numpy.ndarray存超大稀疏矩阵是因内存需求从TB级降至MB级;构造时按场景选格式:coo适合批量构建,lil适合动态插入,csr/csc适合行/列操作;避免toarray()和不安全运算,始终警惕稀疏性丢失。

为什么用 scipy.sparse 而不是 numpy.ndarray
直接存一个 100 万 × 100 万的矩阵,哪怕全是 0,numpy.ndarray 也会吃掉约 8 TB 内存(按 float64 算)。scipy.sparse 只存非零值及其位置,内存占用从 GB 级降到 MB 级——这不是优化,是“能跑起来”的前提。
但别一上来就选 csr_matrix:它适合行切片和矩阵乘法,但逐个赋值(比如 mat[i, j] = x)极慢;而 lil_matrix 支持高效逐元素插入,却不能直接参与计算——得先转成 csr 或 csc 才行。
构造稀疏矩阵时该选哪种格式
常见错误:用循环反复给 csr_matrix 赋值,结果卡死。正确做法是「攒够再建」:
- 已知所有非零位置和值 → 用
coo_matrix((data, (row, col)), shape=(m, n)),最快最稳 - 边读数据边构建(如解析日志、用户行为流)→ 先用
lil_matrix((m, n)),最后调用.tocsr() - 要频繁按行取子矩阵(如推荐系统中取某用户所有交互)→ 构造完立刻转
csr_matrix - 要频繁按列操作(如特征归一化)→ 用
csc_matrix,避免转置开销
toarray() 是性能杀手,多数时候根本不需要调用
很多人习惯性写 mat.toarray() 想“看看数据”,结果内存爆掉或卡住。记住:toarray() 会把整个稀疏结构展开成稠密数组,完全抵消稀疏优势。
立即学习“Python免费学习笔记(深入)”;
替代方案:
- 查形状和非零元数量:
mat.shape,mat.nnz - 看前几行非零项:
mat.tocoo().row[:10],mat.tocoo().col[:10],mat.tocoo().data[:10] - 抽样检查:
mat[0:100, 0:100].toarray()(只取小块) - 保存调试用:
scipy.io.mmwrite('debug.mtx', mat),用文本编辑器或mmread查看
乘法、求逆、解方程这些操作有隐含陷阱
scipy.sparse 的运算不总返回稀疏矩阵——比如 mat @ mat.T 可能产生大量新非零元,结果变稠密;np.linalg.inv(mat) 直接报错,因为稀疏矩阵没有通用逆矩阵概念。
安全做法:
- 矩阵乘法后检查密度:
result.nnz / (result.shape[0] * result.shape[1]),若 > 5%,考虑换算法或降维 - 解线性方程组用
scipy.sparse.linalg.spsolve(A, b),不是np.linalg.solve - 求特征向量用
scipy.sparse.linalg.eigs或svds,传参时务必设k(要多少个),否则默认 k=6,但底层可能尝试全算 - 归一化列向量?别用
mat.sum(axis=0)得到 dense array,改用mat.sum(axis=0).A1(返回 1D numpy 数组)
真正难的不是选哪个格式,而是每次操作前都得问一句:这一步会不会悄悄把稀疏性吃掉?


















