求非只读numpy索引方法:实现指定子矩阵的修改赋值
解决Numpy中高级索引赋值只读的问题
嘿,我完全懂你碰到的这个坑——当你用a[[1,2],...][...,[1,2]]这种两次索引的方式时,其实你操作的是原数组的副本而非视图,所以修改后原数组a根本不会变。要直接修改原数组里的目标区域(也就是(1,1)、(1,2)、(2,1)、(2,2)这四个位置),有几个简单的方法:
方法1:用np.ix_生成可写的区域索引
np.ix_是Numpy专门用来处理这类多维区域索引的工具,它能把行和列的一维索引转换成可以正确广播的索引器,确保你拿到的是原数组的视图,赋值会直接生效:
import numpy as np a = np.random.rand(5,5) # 直接修改原数组的目标区域 a[np.ix_([1,2], [1,2])] = 0
这样写就和你想要的A[[i,j],...][...,[a,b]]的逻辑一致,但能直接修改原数组。
方法2:手动构造笛卡尔积索引
如果你不想用np.ix_,也可以把所有目标位置的行和列索引单独列出来,直接一次索引赋值:
# 构造所有目标坐标的行、列索引 rows = [1, 1, 2, 2] cols = [1, 2, 1, 2] a[rows, cols] = 0
这种方式也能直接修改原数组,因为是一次完成高级索引,不会产生中间副本。
为什么之前的写法不行?
你之前的a[[1,2],...][...,[1,2]],第一次a[[1,2],...]用高级索引提取了第1、2行,这一步返回的是原数组的副本(Numpy中高级索引默认返回副本),之后对这个副本做第二次索引赋值,自然不会影响原数组a。而np.ix_的作用就是把行和列索引组合成一个能直接索引原数组的二维区域的结构,避免了中间副本的产生。
另外如果你后续要处理稀疏矩阵(比如scipy.sparse里的矩阵),修改指定元素的方式会略有不同,但针对普通Numpy数组,上面两种方法完全能解决你的需求。
内容的提问来源于stack exchange,提问作者Fettabernett
相关产品推荐
相关产品推荐

