Aer*_*ngy 7 python numpy python-3.x numba
我有一些大型数组(约1亿个点),我需要以交互方式绘制.我当前正在使用Matplotlib.按原样绘制数组变得非常慢并且是浪费,因为无论如何你都无法想象那么多点.
所以我做了一个min/max抽取函数,我将其绑定到轴的'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
Run Code Online (Sandbox Code Playgroud)
这种方法效果非常好并且足够快(在1e8点和2k箱上约80ms).由于它会定期重新计算和更新线的x和y数据,所以滞后很少.
但是,我唯一的抱怨是x数据.此代码复制每个bin的左边缘的x值,并且不返回y min/max对的真实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
Run Code Online (Sandbox Code Playgroud)
这在我的机器上花了大约400多毫秒,这变得非常明显.所以我的问题基本上是有一种方法可以更快地提供相同的结果吗?瓶颈主要是在numpy.argmin和numpy.argmax它比慢好位功能numpy.min和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.
Run Code Online (Sandbox Code Playgroud)
我设法通过直接使用输出arg(min|max)来索引数据数组来提高性能。这是以额外调用为代价的,np.sort但要排序的轴只有两个元素(最小/最大索引),并且整个数组相当小(箱数):
def min_max_downsample_v3(x, y, num_bins):\n pts_per_bin = x.size // num_bins\n\n x_view = x[:pts_per_bin*num_bins].reshape(num_bins, pts_per_bin)\n y_view = y[:pts_per_bin*num_bins].reshape(num_bins, pts_per_bin)\n i_min = np.argmin(y_view, axis=1)\n i_max = np.argmax(y_view, axis=1)\n\n r_index = np.repeat(np.arange(num_bins), 2)\n c_index = np.sort(np.stack((i_min, i_max), axis=1)).ravel()\n\n return x_view[r_index, c_index], y_view[r_index, c_index]\nRun Code Online (Sandbox Code Playgroud)\n\n我检查了你的例子的时间,我得到了:
\n\nmin_max_downsample_v1: 110 毫秒 \xc2\xb1 5 毫秒min_max_downsample_v2: 240 毫秒 \xc2\xb1 8.01 毫秒min_max_downsample_v3: 164 毫秒 \xc2\xb1 1.23 毫秒我还检查了在致电后直接返回arg(min|max),结果同样为 164 毫秒,即此后不再有真正的开销。