Numpy数组切片与for循环结果比较

2 投票
1 回答
1520 浏览
提问于 2025-04-17 18:32

想象一个由不同密度的壳组成的球体。
我有两个数组,一个是每个壳的外半径(rad[]),另一个是每个壳的密度(den[])。我想计算到某个特定半径的质量,这个质量用mass[]来表示。

下面这个循环的方法可以得到我想要的结果。它首先计算最里面那个壳的质量(因为内半径是零,所以它就是一个球),然后再计算每个后续壳的质量,并把它加到之前的总质量上:

mass = numpy.zeros(len(rad))                                   # create array
mass[0] = den[0]**(rad[0]**3)                                  # find inner sphere mass
for i in range(1,len(mass)):
    mass[i] = mass[i-1] + den[i]*(rad[i]**3 - rad[i-1]**3)     # Find mass out to shell i

注意:我只需要比例,所以对π的具体数值不太在意。

有没有人能解释一下,为什么下面这个切片的结果达不到同样的效果呢?

mass = numpy.zeros(len(rad))
mass[0]  = den[0]*(rad[0]**3)
mass[1:] = mass[0:-1] + den[1:]*(rad[1:]**3-rad[0:-1]**3)

1 个回答

3

原因在于,numpy数组中的所有元素会同时计算。在你第二行的数组 mass[0:-1] 中,它会被计算为 den[0]*(rad[0]**3),后面跟着的就是一堆零。(即使 mass[1] 在计算完成后不再是零,这个也没关系——到那时已经太晚了)。

你提到的例子:

test = numpy.linspace(1,10,num=10)
test[1:] += test[0:-1]
# [  1.   3.   6.  10.  15.  21.  28.  36.  45.  55.]

表现得不一样,仿佛加法是逐步进行的。你例子中的不同之处在于,右边加了一个值——这个加法让它在内存中变成了一个新数组(x + yx 不是同一个数组),这样 numpy 就不再把它当作是对自身的加法了。看看这个例子

test = numpy.linspace(1,10,num=10)
test[1:] += test[0:-1] + 0
# [  1.   3.   5.   7.   9.  11.  13.  15.  17.  19.]

如果你想把你的for循环做成向量化的版本,可以这样做:

mass[1:] += den[1:]*(rad[1:]**3-rad[0:-1]**3)
mass[1:] += mass[0:-1]

撰写回答