У меня есть несколько больших массивов (~ 100 миллионов точек), которые мне нужно построить в интерактивном режиме. В настоящее время я использую 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
Это работает очень хорошо и достаточно быстро (~ 80 мс на 1e8 точек и 2k бинов). Задержка очень небольшая, так как он периодически пересчитывает и обновляет данные x и y линии.
Тем не менее, моя единственная жалоба заключается в x-данных. Этот код дублирует x-значение левого края каждой ячейки и не возвращает истинное x-местоположение пар y min/max. Я обычно устанавливаю количество бинов, чтобы удвоить ширину пикселя оси. Таким образом, вы не можете увидеть разницу, потому что контейнеры такие маленькие... но я знаю, что она есть... и это меня раздражает.
Итак, попытка № 2, которая возвращает фактические значения x для каждой пары min/max. Однако это примерно в 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
и numpy.argmax
, которые немного медленнее, чем numpy.min
и numpy.max
.
Ответ может заключаться в том, чтобы просто жить с версией № 1, поскольку визуально она не имеет большого значения. Или, может быть, попытаться ускорить его чем-то вроде cython (который я никогда не использовал).
К вашему сведению, использование Python 3.6.4 в Windows... пример использования будет примерно таким:
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.
set_data
существующей строки в matplotlib. - person user2699   schedule 31.01.2019