You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Pandas DataFrame的值覆盖Scipy稀疏COO矩阵

用NumPy向量化替代Pandas apply更新Scipy COO矩阵

我用Scipy构建了一个稀疏COO矩阵,示例数据如下:

(100981, 0)   0.015
  (100982, 0)   0.016
  (100983, 0)   0.016
  (100981, 1)   0.023
  (100982, 1)   0.024
  (100983, 1)   0.025
  (100981, 2)   0.019
  (100982, 2)   0.018
  (100983, 2)   0.017

同时有一个Pandas DataFrame,结构如下:

site_0   site_1   site_2    site
0  0.0140  0.02313  0.01020  100981
1  0.0130  0.02200  0.01370  100982
2  0.0162  0.02510  0.01479  100983

原先用Pandas apply逐行更新矩阵的代码:

# where v_coo is my matrix defined above
# where df is my dataframe defined above
def override_sites(row):
    v_coo[row['site'], 0] = row['site_0']
    v_coo[row['site'], 1] = row['site_1']
    v_coo[row['site'], 2] = row['site_2']
    return v_coo
df.apply(override_sites, axis=1)

问题说明

apply逐行更新效率极低,而且COO矩阵本身是不可变类型,每次赋值都会触发内部类型转换,性能损耗很大。下面是两种用NumPy向量化实现的高效方案:


方案1:转CSR矩阵后批量更新

CSR矩阵支持基于坐标的批量赋值,适合保留原矩阵大部分条目、仅更新小部分的场景:

import numpy as np
from scipy.sparse import csr_matrix

# 1. 将原COO矩阵转为CSR(支持高效赋值操作)
v_csr = v_coo.tocsr()

# 2. 构造向量化的行、列索引和对应值
rows = df['site'].repeat(3).values  # 每个site对应3列,重复3次
cols = np.tile([0, 1, 2], len(df))  # 列索引循环生成[0,1,2]
values = df[['site_0', 'site_1', 'site_2']].values.flatten()  # 扁平化所有待更新值

# 3. 批量更新矩阵
v_csr[rows, cols] = values

# 若需转回COO格式
v_coo_updated = v_csr.tocoo()

方案2:直接构造新的COO矩阵

利用COO矩阵基于row/col/data数组存储的特性,直接合并原矩阵条目和更新条目,去重后生成最终矩阵,适合大规模数据场景:

import numpy as np
from scipy.sparse import coo_matrix

# 1. 提取原COO矩阵的核心数据
orig_rows = v_coo.row
orig_cols = v_coo.col
orig_data = v_coo.data

# 2. 构造DataFrame对应的更新条目
update_rows = df['site'].repeat(3).values
update_cols = np.tile([0, 1, 2], len(df))
update_data = df[['site_0', 'site_1', 'site_2']].values.flatten()

# 3. 合并原条目与更新条目
all_rows = np.concatenate([orig_rows, update_rows])
all_cols = np.concatenate([orig_cols, update_cols])
all_data = np.concatenate([orig_data, update_data])

# 4. 去重:保留每个(row,col)对的最后一个值(即更新后的值)
coord_pairs = np.stack([all_rows, all_cols], axis=1)
_, unique_idx = np.unique(coord_pairs, axis=0, return_index=True)
unique_idx = np.sort(unique_idx)  # 可选:保持索引顺序,不影响矩阵内容

# 5. 生成更新后的COO矩阵
v_coo_updated = coo_matrix(
    (all_data[unique_idx], (all_rows[unique_idx], all_cols[unique_idx])),
    shape=v_coo.shape
)

为什么这两种方法更高效

所有操作都是基于NumPy数组的批量运算,完全避免了逐行循环,效率比apply高几个数量级,数据量越大优势越明显。

内容的提问来源于stack exchange,提问作者mp252

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 15:45:36