我有一些大型数组(约 1 亿点)需要以交互方式绘制。我目前正在使用 Matplotlib。按原样绘制数组会变得非常慢并且很浪费,因为无论如何您都无法可视化那么多点。
因此,我创建了一个最小/最大抽取函数,并将其与轴的“xlim_changed”回调绑定在一起。我采用了最小/最大方法,因为数据包含快速峰值,我不想通过单步浏览数据而错过这些峰值。还有更多包装器会裁剪到 x 限制,并在某些条件下跳过处理,但相关部分如下:
def min_max_downsample(x,y,num_bins):
""" Break the data into num_bins and returns min/max for each bin"""
pts_per_bin = x.size // num_bins
#Create temp to hold the reshaped & slightly cropped y
y_temp = y[:num_bins*pts_per_bin].reshape((num_bins, pts_per_bin))
y_out = np.empty((num_bins,2))
#Take the min/max by rows.
y_out[:,0] = y_temp.max(axis=1)
y_out[:,1] = y_temp.min(axis=1)
y_out = y_out.ravel()
#This duplicates the x-value for each min/max y-pair
x_out = np.empty((num_bins,2))
x_out[:] = x[:num_bins*pts_per_bin:pts_per_bin,np.newaxis]
x_out = x_out.ravel()
return x_out, y_out
这工作得很好并且足够快(在 1e8 点和 2k bin 上约为 80 毫秒)。由于它定期重新计算和更新线路的 x 和 y 数据,因此几乎没有延迟。
然而,我唯一的抱怨是 x 数据。此代码复制每个 bin 左边缘的 x 值,并且不返回 y 最小/最大对的真实 x 位置。我通常将箱数设置为轴像素宽度的两倍。所以你真的看不出区别,因为垃圾箱太小了……但我知道它在那里……这让我很烦恼。
因此,尝试第 2 种方法,它确实返回每个最小/最大对的实际 x 值。然而,速度慢了大约 5 倍。
def min_max_downsample_v2(x,y,num_bins):
pts_per_bin = x.size // num_bins
#Create temp to hold the reshaped & slightly cropped y
y_temp = y[:num_bins*pts_per_bin].reshape((num_bins, pts_per_bin))
#use argmax/min to get column locations
cc_max = y_temp.argmax(axis=1)
cc_min = y_temp.argmin(axis=1)
rr = np.arange(0,num_bins)
#compute the flat index to where these are
flat_max = cc_max + rr*pts_per_bin
flat_min = cc_min + rr*pts_per_bin
#Create a boolean mask of these locations
mm_mask = np.full((x.size,), False)
mm_mask[flat_max] = True
mm_mask[flat_min] = True
x_out = x[mm_mask]
y_out = y[mm_mask]
return x_out, y_out
在我的机器上,这大约需要 400 多毫秒,这变得非常明显。所以我的问题基本上是有没有办法更快并提供相同的结果?瓶颈主要在于numpy.argmin
and numpy.argmax
比以下函数慢一点numpy.min
and numpy.max
.
答案可能是只接受版本#1,因为它在视觉上并不重要。或者尝试加快速度,例如 cython (我从未使用过)。
仅供参考,在 Windows 上使用 Python 3.6.4 ...示例用法如下:
x_big = np.linspace(0,10,100000000)
y_big = np.cos(x_big )
x_small, y_small = min_max_downsample(x_big ,y_big ,2000) #Fast but not exactly correct.
x_small, y_small = min_max_downsample_v2(x_big ,y_big ,2000) #correct but not exactly fast.