我猜您正在使用Python 2,但如果不是,计算步长时应将除法更改为//
(地板除法),否则numpy将无法将浮点数解释为步长而感到烦恼。
binwidth = numpy.max(rev_count)//10
revbin = range(0, numpy.max(rev_count), binwidth)
revbinnedstars = [None]*len(revbin)
for i in range(0, len(revbin)-1):
index1 = revbin[i]-binwidth/2 < rev_count
index2 = rev_count < revbin[i]+binwidth/2)
revbinnedstars[i] = numpy.mean(stars[np.logical_and(index1, index2)])
至少这个方法可以工作并给出正确的结果。如果您有大型数据集并且想要超过10个bin,那么这将非常低效。
一个非常重要的收获:
- 如果要索引数组,请不要使用
np.argwhere
。该结果仅应为“人类可读”。如果您确实想要坐标,请使用np.where
。它可以用作索引,但如果输入是多维的,则不太容易阅读。
numpy documentation在这一点上支持我:
argwhere的输出不适合用于索引数组。为此,请改用where(a)。
这也是您的代码如此缓慢的原因。它试图做一些您不想要的事情,并且在内存和CPU使用方面可能非常昂贵。而且还无法给您正确的结果。
我在这里所做的被称为
布尔掩码。它比
np.where(condition)
更短,并且少了一个计算步骤。
完全矢量化的方法可以通过定义一个网格来使用,该网格知道哪些星星在哪个箱子中:
bins = 10
binwidth = numpy.max(rev_count)//bins
revbin = np.arange(0, np.max(rev_count)+binwidth+1, binwidth)
更好的定义区间的方法是,要注意将最大值加一,因为你想要包括它,并且将区间数加一,因为你关心的是区间的起始和结束点而不是区间的中心:
number_of_bins = 10
revbin = np.linspace(np.min(rev_count), np.max(rev_count)+1, number_of_bins+1)
然后你可以设置网格:
grid = np.logical_and(rev_count[None, :] >= revbin[:-1, None], rev_count[None, :] < revbin[1:, None])
网格大小为
bins
x
rev_count
(由于广播的缘故,我增加了每个数组的维度,但并不相同)。这本质上检查一个点是否大于下限范围并且小于上限范围(因此使用了
[:-1]
和
[1:]
索引)。这是在多维中完成的,其中计数在第二维(numpy轴=1)中,而bin在第一维(numpy轴=0)中。
因此,我们可以通过将这些与该网格相乘来获取星星在适当bin中的Y坐标。
stars * grid
为了计算平均值,我们需要该区间坐标的总和并将其除以该区间中星星的数量(区间沿
axis=1
,不在该区间内的星星在此轴上仅具有零值)。
revbinnedstars = np.sum(stars * grid, axis=1) / np.sum(grid, axis=1)
我其实不知道那样是否更有效率。它会占用更多的内存,但或许在 CPU 上会稍微节省一些。