Numpy掩码直接书写和预存为变量使用时行为不一致是什么原因?
问题原因解答
核心差异来自Numpy布尔掩码的计算时机,两种写法的逻辑本质并不相同:
- 第一种直接写条件的写法,每次操作都会基于当前的数组值重新计算掩码:
你先把fizzbuzz位置赋值为9998之后,后续执行a[a % 3 == 0] = 9993、a[a % 5 == 0] = 9995时,是用修改后的a重新计算满足条件的位置,此时9998既不能被3整除也不能被5整除,所以原来的fizzbuzz位置不会被选中,自然不会被后续赋值覆盖。 - 第二种预存掩码的写法,掩码是固定不变的静态值:
你提前定义的fizz、buzz是基于最原始的np.arange(32)计算得到的布尔数组,一旦生成就不会跟随a的修改自动更新。也就是说不管a后续的值怎么改,fizz里标记为True的永远是初始状态下能被3整除的索引(0、3、6……30),buzz里标记为True的永远是初始状态下能被5整除的索引(0、5、10……30)。
所以哪怕你先把索引0、15、30的位置改成了9998,后续执行a[fizz] = 9993时还是会把这些初始满足条件的索引全部修改,最后a[buzz] = 9995又会再覆盖一次,导致原来的9998被替换。
你提到的“将a[fizzbuzz]替换为a[fizz & buzz]也无法解决”也是同理:fizz和buzz本身就是预存的静态布尔数组,做与运算的结果还是基于初始数组的索引标记,不会重新基于修改后的a计算条件。
正确实现参考
如果想要预存掩码提升效率,只需要在后续赋值时排除fizzbuzz的位置即可:
import numpy as np a = np.arange(32) fizz = (a % 3 == 0) buzz = (a % 5 == 0) fizzbuzz = fizz & buzz a[fizzbuzz] = 9998 a[fizz & ~fizzbuzz] = 9993 # 仅修改属于fizz但不属于fizzbuzz的位置 a[buzz & ~fizzbuzz] = 9995 # 仅修改属于buzz但不属于fizzbuzz的位置
内容的提问来源于stack exchange,提问作者Bozhidar Dimitrov
相关产品推荐
相关产品推荐

