选csc_matrix还是csr_matrix取决于操作方向:列切片用csc_matrix,行切片用csr_matrix;coo_matrix仅适用于构造阶段,需转为csr/csc才能运算;lil_matrix仅适合动态构建,完成后必须转换;拼接矩阵前须统一格式并校验形状。

稀疏矩阵该选 csc_matrix 还是 csr_matrix?
取决于你主要做「列切片」还是「行切片」——csc_matrix(Compressed Sparse Column)对列操作快,csr_matrix(Compressed Sparse Row)对行操作快。底层是用三个数组存非零值、行索引、列指针(或反之),结构差异直接决定访问效率。
常见错误现象:mat[:, 5] 在 csr_matrix 上会触发全矩阵转置再切片,慢得离谱;反过来,mat[3, :] 在 csc_matrix 上也一样。
- 做特征提取、按列标准化(比如每列减均值)→ 优先用
csc_matrix - 做样本采样、按行计算 L2 范数、批量预测 → 优先用
csr_matrix - 从
scipy.sparse.load_npz()加载后默认是csr,别直接拿去列操作 - 转换开销不可忽略:
mat.tocsc()或mat.tocsr()是 O(nnz) 时间,不是常数
coo_matrix 为什么不能直接做乘法?
coo_matrix 是最原始的三元组格式(行索引、列索引、值),不支持算术运算和切片,因为没建索引结构——它连「某行有哪些非零元」都得遍历找。
使用场景:只适合构造阶段。比如从文件逐行读取 (i, j, val),append 到三个列表里,最后一次性转成 coo_matrix,再立刻转成 csr 或 csc。
- 误用
coo_matrix做@矩阵乘 → 报错TypeError: unsupported operand type(s) for @: 'coo_matrix' and 'coo_matrix' coo_matrix允许重复 (i,j),但转成csr/csc时会自动求和,这是隐式行为,容易漏掉数据异常- 构造完必须转:用
.tocsr()或.tocsc(),别留着coo做后续计算
lil_matrix 适合动态插入,但千万别用它存最终结果
lil_matrix(List of Lists)内部用 Python 列表存每行的列索引和值,支持 mat[i, j] = x 这种随机写入,但内存占用高、访问慢、不支持广播运算。
性能影响明显:10 万行 × 10 万列的稀疏矩阵,用 lil 存可能吃掉 2–3 倍内存,且 mat.sum(axis=1) 比 csr 慢一个数量级。
- 只在「边生成边填」场景用:比如迭代算法中逐行构造矩阵
- 填完立刻转:
mat.tocsr()是标准收尾动作,不是可选项 - 别用
lil_matrix做np.dot或传给sklearn模型——很多模型内部会检查格式,遇到lil直接报ValueError: Expected CSR or CSC matrix
用 scipy.sparse.bmat 拼接矩阵时维度对不上怎么办?
bmat 要求子块在逻辑上能排成矩形,比如 [[A, B], [C, D]] 中,A.shape[0] 必须等于 C.shape[0],A.shape[1] 等于 B.shape[1],否则报 ValueError: blocks must be 2-D 或更模糊的 inconsistent shapes。
容易踩的坑是混用不同格式:比如 A 是 csr,B 是 coo,bmat 不会自动统一,可能在拼接中途因格式不兼容崩掉。
- 拼之前先统一格式:
A.tocsr(), B.tocsr(), C.tocsr(), D.tocsr() - 手动校验形状:
assert A.shape[0] == C.shape[0]和assert A.shape[1] == B.shape[1],比看报错信息快得多 - 如果只是水平拼(
[A, B]),用scipy.sparse.hstack([A, B])更稳;垂直拼用vstack,它们对形状要求更明确,报错也更直白
稀疏格式转换不是“无感”的,每次 .tocsr() 都在重排数据;而不同格式对同一操作的时间差可以到百倍。真正卡住你的往往不是算法,而是矩阵刚加载完就用错了格式。