我想您使用的是 Python 2,但如果不是,您应该在计算步长时将除法更改为 //(地板除法),否则 numpy 会因为无法将浮点数解释为步长而烦恼。
binwidth = numpy.max(rev_count)//10 # Changed this to floor division
revbin = range(0, numpy.max(rev_count), binwidth)
revbinnedstars = [None]*len(revbin)
for i in range(0, len(revbin)-1):
# I actually don't know what you wanted to do but I guess you wanted the
# "logical and" combination in that bin (you don't need to use np.where here)
# You can put that all in one statement but it gets crowded so I'll split it:
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 使用方面可能非常昂贵。没有给你正确的结果。
我在这里所做的称为boolean masks。比np.where(condition)写的更短,计算量也少。
可以通过定义一个知道哪些星星在哪个 bin 中的网格来使用完全矢量化的方法:
bins = 10
binwidth = numpy.max(rev_count)//bins
revbin = np.arange(0, np.max(rev_count)+binwidth+1, binwidth)
定义垃圾箱的更好方法是。请注意,您必须将最大值添加到最大值,因为您想将它包含在内,并且将一到 bin 的数量,因为您对 bin-start 和 end-points 感兴趣,而不是 bin 的中心:
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 大(因为广播,我将每个数组的维度增加了一个但不一样)。这实质上检查一个点是否大于下 bin 范围并小于上 bin 范围(因此是 [:-1] 和 [1:] 索引)。这是多维完成的,其中计数在第二维(numpy 轴 = 1)和箱在第一维(numpy 轴 = 0)
所以我们可以通过将这些与这个网格相乘来获得适当 bin 中星星的 Y 坐标:
stars * grid
要计算平均值,我们需要将这个 bin 中的坐标总和除以该 bin 中的星数(bin 沿axis=1,不在这个 bin 中的星只有零值沿着这个轴):
revbinnedstars = np.sum(stars * grid, axis=1) / np.sum(grid, axis=1)
我实际上不知道这是否更有效。它在内存上会贵很多,但在 CPU 上可能会便宜一些。