使用索引与布尔选择更新二维矩阵值失败求助
解决Numpy数组链式索引赋值不生效的问题
我来帮你搞定这个赋值没生效的问题!核心原因是你用了链式索引(也就是array[a][b]这种形式),Numpy在这种情况下返回的是数组的副本而非原数组的视图,所以你修改的只是临时副本,原数组center_mindists自然不会有变化。
问题根源拆解
你原来的代码里:
center_mindists[id0, max_min_idx][lower_idx] = distances[lower_idx[0]]
center_mindists[id0, max_min_idx]会返回一个新的一维数组(从每行取最大距离对应的元素),接着[lower_idx]是对这个新数组做索引,得到的是它的副本。赋值操作只会修改这个副本,和原数组完全没关系。
修正后的代码实现
首先先纠正一个小笔误:你代码里的centers_mindists应该是center_mindists,另外计算距离时要加上axis=1才能得到每行的距离(不然会返回所有元素的总和)。下面是完整的修正方案:
import numpy as np # 初始化数据 elems = np.array([[5, 5],[4, 4],[8, 8]]) k = 2 center_mindists = np.full((len(elems), k), np.inf) x = np.array([1, 1]) # 计算新元素与所有已有元素的距离 distances = np.sum(np.abs(elems - x), axis=1) # 结果为 [8, 6, 14] # 找到每行当前存储的最大距离的索引 max_min_idx = np.argmax(center_mindists, axis=1) # 初始为 [0, 0, 0] # 构造掩码:筛选出当前最大距离大于新距离的行 mask = distances < center_mindists[np.arange(len(center_mindists)), max_min_idx] # 直接通过掩码索引更新原数组 center_mindists[mask, max_min_idx[mask]] = distances[mask]
执行后center_mindists会变成:
array([[8., inf], [6., inf], [14., inf]])
完全符合预期!
关键原理说明
用center_mindists[mask, max_min_idx[mask]]这种一次性索引的方式,Numpy会直接定位到原数组中需要修改的元素位置,返回的是原数组的视图,赋值操作会直接作用于原数组,这才是正确的修改姿势。
如果后续你需要维护每行的k个最小距离(比如新元素可能比多个已存储的距离小),可以考虑用np.partition来快速找到每行的k个最小值,不过当前场景下,替换每行最大的那个元素,上面的方法已经足够高效啦。
内容的提问来源于stack exchange,提问作者Ferradest
相关产品推荐
相关产品推荐

