Ускорить Matplotlib?
Я прочитал здесь, что matplotlib хорошо справляется с большими наборами данных. Я пишу приложение обработки данных и имеет встроенные графики matplotlib в wx и обнаружил, что matplotlib является TERRIBLE при обработке больших объемов данных, как с точки зрения скорости, так и с точки зрения памяти. Кто-нибудь знает способ ускорить (уменьшить размер памяти) matplotlib, кроме понижающей дискретизации ваших входов?
Чтобы проиллюстрировать, как плохой matplotlib с памятью рассмотрит этот код:
import pylab
import numpy
a = numpy.arange(int(1e7)) # only 10,000,000 32-bit integers (~40 Mb in memory)
# watch your system memory now...
pylab.plot(a) # this uses over 230 ADDITIONAL Mb of memory
Ответы
Ответ 1
Даунсэмплинга - хорошее решение здесь - построение точек 10M потребляет кучу памяти и времени в matplotlib. Если вы знаете, сколько памяти приемлемо, вы можете уменьшить размер на основе этой суммы. Например, допустим, что 1M точек занимает 23 дополнительных МБ памяти, и вы считаете, что это приемлемо с точки зрения пространства и времени, поэтому вы должны уменьшить размер так, чтобы он всегда находился ниже 1M точек:
if(len(a) > 1M):
a = scipy.signal.decimate(a, int(len(a)/1M)+1)
pylab.plot(a)
Или что-то вроде приведенного выше фрагмента (приведенное выше может слишком сильно понижать для вашего вкуса.)
Ответ 2
Меня часто интересуют экстремальные значения, поэтому, прежде чем строить большие куски данных, я продолжаю так:
import numpy as np
s = np.random.normal(size=(1e7,))
decimation_factor = 10
s = np.max(s.reshape(-1,decimation_factor),axis=1)
# To check the final size
s.shape
Конечно, np.max
является просто примером экстремальной функции вычисления.
P.S.
При использовании numpy
"шаганий трюков" должно быть возможно избежать копирования данных во время изменения формы.
Ответ 3
Я был заинтересован в сохранении одной стороны графика выборки, так что я придумал следующее: (первая попытка даунсамплинга)
def downsample(x, y, target_length=1000, preserve_ends=0):
assert len(x.shape) == 1
assert len(y.shape) == 1
data = np.vstack((x, y))
if preserve_ends > 0:
l, data, r = np.split(data, (preserve_ends, -preserve_ends), axis=1)
interval = int(data.shape[1] / target_length) + 1
data = data[:, ::interval]
if preserve_ends > 0:
data = np.concatenate([l, data, r], axis=1)
return data[0, :], data[1, :]
def geom_ind(stop, num=50):
geo_num = num
ind = np.geomspace(1, stop, dtype=int, num=geo_num)
while len(set(ind)) < num - 1:
geo_num += 1
ind = np.geomspace(1, stop, dtype=int, num=geo_num)
return np.sort(list(set(ind) | {0}))
def log_downsample(x, y, target_length=1000, flip=False):
assert len(x.shape) == 1
assert len(y.shape) == 1
data = np.vstack((x, y))
if flip:
data = np.fliplr(data)
data = data[:, geom_ind(data.shape[1], num=target_length)]
if flip:
data = np.fliplr(data)
return data[0, :], data[1, :]
что позволило мне лучше сохранить одну сторону сюжета:
newx, newy = downsample(x, y, target_length=1000, preserve_ends=50)
newlogx, newlogy = log_downsample(x, y, target_length=1000)
f = plt.figure()
plt.gca().set_yscale("log")
plt.step(x, y, label="original")
plt.step(newx, newy, label="downsample")
plt.step(newlogx, newlogy, label="log_downsample")
plt.legend()
![test]()