如何快速对大型scipy csr矩阵的每两行进行求和?
高效实现CSR矩阵每两行求和的方法
针对你的大型CSR矩阵(250k行,2.5M列),无需转换为稠密数组,推荐使用稀疏矩阵乘法的方式实现逐行分组求和,这是效率最高的方案之一,完全利用Scipy稀疏矩阵的优化操作。
具体实现步骤
核心思路是构造一个稀疏转换矩阵,将原矩阵的每两行映射到新矩阵的一行,再通过矩阵乘法完成求和:
import numpy as np from scipy import sparse # 假设原CSR矩阵为X,shape=(250000, 2500000) n_original_rows = X.shape[0] n_new_rows = n_original_rows // 2 # 125000行 # 构造稀疏转换矩阵A:shape=(125000, 2500000),每行对应原矩阵的两行 data = np.ones(n_original_rows, dtype=X.dtype) indices = np.arange(n_original_rows) indptr = np.arange(0, n_original_rows + 1, 2) # 每2个原行对应1个新行 A = sparse.csr_matrix((data, indices, indptr), shape=(n_new_rows, n_original_rows)) # 执行矩阵乘法,得到结果矩阵 result_matrix = A.dot(X)
方案优势
- 内存友好:转换矩阵
A仅存储250k个非零元素(全为1),内存占用极低,完全避免稠密数组的内存爆炸问题。 - 速度高效:Scipy的稀疏矩阵乘法基于C优化实现,远快于Python层面的逐行迭代。
- 代码简洁:无需复杂的行遍历和元素合并逻辑,利用矩阵运算天然实现分组求和。
备选优化方案(直接操作CSR内部结构)
如果需要更精细控制内存,也可以直接操作CSR矩阵的data、indices、indptr属性,逐对合并行并求和重复列:
new_indptr = np.zeros(n_new_rows + 1, dtype=np.int64) new_data = [] new_indices = [] for i in range(n_new_rows): # 获取当前两行的索引和数据范围 row1_start, row1_end = X.indptr[2*i], X.indptr[2*i+1] row2_start, row2_end = X.indptr[2*i+1], X.indptr[2*i+2] # 合并两行的列索引和对应值 combined_indices = np.concatenate([X.indices[row1_start:row1_end], X.indices[row2_start:row2_end]]) combined_data = np.concatenate([X.data[row1_start:row1_end], X.data[row2_start:row2_end]]) # 对重复列求和 unique_cols, idx = np.unique(combined_indices, return_inverse=True) summed_vals = np.bincount(idx, weights=combined_data) new_indices.append(unique_cols) new_data.append(summed_vals) new_indptr[i+1] = new_indptr[i] + len(unique_cols) # 构建新的CSR矩阵 new_data = np.concatenate(new_data) new_indices = np.concatenate(new_indices) result_matrix = sparse.csr_matrix((new_data, new_indices, new_indptr), shape=(n_new_rows, X.shape[1]))
这个方案的内存占用略低于矩阵乘法,但速度稍慢(因为涉及Python循环),适合对内存极限优化的场景。
内容的提问来源于stack exchange,提问作者hawk.q852
相关产品推荐
相关产品推荐

