Есть ли функция PyiPy или функция или модуль NumPy для Python, которая вычисляет среднее значение для одномерного массива в конкретном окне?
python
numpy
scipy
moving-average
Shejo284
источник
источник
UPD: более эффективные решения были предложены Alleo и jasaarim .
Вы можете использовать
np.convolve
для этого:объяснение
Скользящее среднее - это случай математической операции свертки . Для скользящего среднего вы перемещаете окно вдоль ввода и вычисляете среднее значение содержимого окна. Для дискретных одномерных сигналов свертка - это то же самое, за исключением того, что вместо среднего вы вычисляете произвольную линейную комбинацию, то есть умножаете каждый элемент на соответствующий коэффициент и суммируете результаты. Эти коэффициенты, по одному для каждой позиции в окне, иногда называют ядром свертки . Теперь среднее арифметическое значений N равно
(x_1 + x_2 + ... + x_N) / N
, так что соответствующее ядро есть(1/N, 1/N, ..., 1/N)
, и это именно то, что мы получаем, используяnp.ones((N,))/N
.Ребра
mode
Аргументnp.convolve
определяет , как обрабатывать края. Я выбралvalid
режим здесь, потому что я думаю, что именно так большинство людей ожидает, что сработает среднее значение, но у вас могут быть другие приоритеты. Вот график, который иллюстрирует разницу между режимами:источник
numpy.cumsum
имеет большую сложность.Эффективное решение
Свертка намного лучше, чем простой подход, но (я думаю) она использует БПФ и, следовательно, довольно медленно. Тем не менее, специально для вычисления среднего значения работает следующий подход
Код для проверки
Обратите внимание , что
numpy.allclose(result1, result2)
естьTrue
два способа эквивалентны. Чем больше N, тем больше разница во времени.предупреждение: хотя cumsum быстрее, будет увеличиваться ошибка с плавающей запятой, которая может привести к тому, что ваши результаты будут недействительными / неправильными / неприемлемыми
комментарии указывают на эту проблему с плавающей запятой здесь, но я делаю это более очевидным здесь, в ответе. ,
np.longdouble
но ваша ошибка с плавающей запятой все еще станет значительной для относительно большого количества точек (около> 1e5, но зависит от ваших данных)источник
numpy.convolve
что O (мн); его документы упоминают, чтоscipy.signal.fftconvolve
использует БПФ.running_mean([1,2,3], 2)
даетarray([1, 2])
. Заменаx
по[float(value) for value in x]
делает трюк.x
содержит поплавки. Пример:running_mean(np.arange(int(1e7))[::-1] + 0.2, 1)[-1] - 0.2
возврат в0.003125
ожидании0.0
. Дополнительная информация: en.wikipedia.org/wiki/Loss_of_significanceОбновление: в приведенном ниже примере показана старая
pandas.rolling_mean
функция, которая была удалена из последних версий панд. Современный эквивалент вызова функции ниже будетПанды больше подходят для этого, чем NumPy или SciPy. Его функция Rolling_mean делает работу удобно. Он также возвращает массив NumPy, когда входные данные являются массивом.
Сложно превзойти
rolling_mean
по производительности любую обычную реализацию Python. Вот пример производительности против двух предложенных решений:Есть также хорошие варианты того, как работать со значениями ребер.
источник
df.rolling(windowsize).mean()
теперь работает вместо (очень быстро, я мог бы добавить). для 6000 рядов строк%timeit test1.rolling(20).mean()
возвращено 1000 циклов, лучшее из 3: 1,16 мс на циклdf.rolling()
работает достаточно хорошо, проблема в том, что даже эта форма не будет поддерживать ndarrays в будущем. Чтобы использовать его, нам нужно сначала загрузить наши данные в Pandas Dataframe. Я хотел бы видеть эту функцию добавляемой либоnumpy
илиscipy.signal
.%timeit bottleneck.move_mean(x, N)
в 3-15 раз быстрее, чем методы cumsum и pandas на моем компьютере. Взгляните на их тест в README .Вы можете рассчитать скользящее среднее с помощью:
Но это медленно.
К счастью, numpy включает в себя функцию сверток, которую мы можем использовать для ускорения работы. Промежуточное среднее эквивалентно свертыванию
x
сN
длинным вектором , причем все члены равны1/N
. Реализация NumPy свертки включает в себя начальный переходный процесс, поэтому вы должны удалить первые N-1 точек:На моей машине быстрая версия работает в 20-30 раз быстрее, в зависимости от длины входного вектора и размера окна усреднения.
Обратите внимание, что в Convolve есть
'same'
режим, который, похоже, должен решать начальную временную проблему, но разделяет его между началом и концом.источник
mode='valid'
вconvolve
которых не требует последующей обработки.mode='valid'
удаляет переходный процесс с обоих концов, верно? Еслиlen(x)=10
иN=4
для среднего значения я бы хотел 10 результатов, ноvalid
вернул бы 7.modes = ('full', 'same', 'valid'); [plot(convolve(ones((200,)), ones((50,))/50, mode=m)) for m in modes]; axis([-10, 251, -.1, 1.1]); legend(modes, loc='lower center')
(с импортированным pyplot и numpy).runningMean
Побочный эффект усреднения с нулями, когда вы выходите из массива сx[ctr:(ctr+N)]
правой стороны массива.runningMeanFast
также есть эта проблема пограничного эффекта.в моих тестах на Tradewave.net TA-lib всегда побеждает:
полученные результаты:
источник
NameError: name 'info' is not defined
, Я получаю эту ошибку, сэр.Готовое решение см. По адресу https://scipy-cookbook.readthedocs.io/items/SignalSmooth.html . Это обеспечивает скользящее среднее с
flat
типом окна. Обратите внимание, что это немного сложнее, чем простой метод «сделай сам», поскольку он пытается обработать проблемы в начале и конце данных, отражая их (что может или не может работать в вашем случае. ..).Для начала вы можете попробовать:
источник
numpy.convolve
разнице только в изменении последовательности.w
размер окна иs
данные?Вы можете использовать scipy.ndimage.filters.uniform_filter1d :
uniform_filter1d
:'reflect'
по умолчанию, но в моем случае, я скорее хотел'nearest'
Это также довольно быстро (почти в 50 раз быстрее
np.convolve
и в 2-5 раз быстрее, чем описанный выше подход к суммированию ):Вот 3 функции, которые позволяют сравнивать ошибки / скорости различных реализаций:
источник
uniform_filter1d
,np.convolve
с прямоугольником, аnp.cumsum
затемnp.subtract
. мои результаты: (1.) Свернуть это самый медленный. (2.) сумма / вычитание примерно в 20-30 раз быстрее. (3. )iform_filter1d примерно в 2-3 раза быстрее, чем сумма / вычитание. Победитель определенно --iform_filter1d.uniform_filter1d
это быстрее , чемcumsum
раствор (примерно 2-5x). иuniform_filter1d
не получает массивную ошибку с плавающей запятой, какcumsum
решение.Я знаю, что это старый вопрос, но вот решение, которое не использует никаких дополнительных структур данных или библиотек. Он линейен по количеству элементов входного списка, и я не могу придумать какой-либо другой способ сделать его более эффективным (на самом деле, если кто-то знает, как лучше распределить результат, пожалуйста, дайте мне знать).
ПРИМЕЧАНИЕ: это было бы намного быстрее, если бы использовать пустой массив вместо списка, но я хотел устранить все зависимости. Также было бы возможно улучшить производительность многопоточным выполнением
Функция предполагает, что входной список является одномерным, поэтому будьте осторожны.
пример
Предположим, у нас есть список,
data = [ 1, 2, 3, 4, 5, 6 ]
по которому мы хотим вычислить скользящее среднее с периодом 3, и что вам также нужен выходной список того же размера, что и входной (это чаще всего так).Первый элемент имеет индекс 0, поэтому скользящее среднее следует вычислять для элементов с индексами -2, -1 и 0. Очевидно, у нас нет данных [-2] и данных [-1] (если вы не хотите использовать специальные граничные условия), поэтому мы предполагаем, что эти элементы равны 0. Это эквивалентно заполнению нулями списка, за исключением того, что мы фактически не дополняем его, просто следим за индексами, которые требуют заполнения (от 0 до N-1).
Итак, для первых N элементов мы просто продолжаем складывать элементы в аккумуляторе.
Из элементов N + 1 вперёд простое накопление не работает. мы ожидаем,
result[3] = (2 + 3 + 4)/3 = 3
но это отличается от(sum + 4)/3 = 3.333
.Способ вычислить правильное значение вычесть
data[0] = 1
изsum+4
, таким образом даваяsum + 4 - 1 = 9
.Это происходит потому
sum = data[0] + data[1] + data[2]
, что в настоящее время , но это также верно для каждого,i >= N
потому что, перед вычитанием,sum
естьdata[i-N] + ... + data[i-2] + data[i-1]
.источник
Я чувствую, что это может быть элегантно решено с помощью узкого места
См основной образец ниже:
«мм» - это скользящее среднее для «а».
«Окно» - это максимальное количество записей, которые нужно учитывать для скользящего среднего.
«min_count» - это минимальное количество записей, которое нужно учитывать для скользящего среднего (например, для первых нескольких элементов или если массив имеет значения nan).
Хорошая часть заключается в том, что «Узкое место» помогает справиться со значениями наночастиц, а также очень эффективно.
источник
Я еще не проверил, насколько это быстро, но вы можете попробовать:
источник
Этот ответ содержит решения, использующие стандартную библиотеку Python для трех различных сценариев.
Скользящее среднее с
itertools.accumulate
Это решение Python 3.2+ с эффективным использованием памяти, вычисляющее скользящее среднее по многократным значениям путем использования
itertools.accumulate
.Обратите внимание, что
values
может быть любая итерация, включая генераторы или любой другой объект, который создает значения на лету.Сначала лениво построим накопленную сумму значений.
Далее
enumerate
кумулятивную сумму (начиная с 1) и построение генератора, который выдает долю накопленных значений и текущий индекс перечисления.Вы можете выдавать,
means = list(rolling_avg)
если вам нужны все значения в памяти одновременно или вызыватьnext
пошагово.(Конечно, вы можете также перебирать
rolling_avg
сfor
петлей, которая будет вызыватьnext
неявно.)Это решение можно записать в виде функции следующим образом.
Сопрограммный , к которому вы можете отправить значение в любое время
Эта сопрограмма использует значения, которые вы ей отправляете, и хранит скользящее среднее от значений, которые вы видели до сих пор.
Это полезно, когда у вас нет итерируемых значений, но вы хотите получить значения, которые будут усредняться по одному в разное время на протяжении всей жизни вашей программы.
Сопрограмма работает так:
Вычисление среднего по скользящему окну размера
N
Эта функция-генератор принимает итеративный размер окна
N
и выдает среднее значение по текущим значениям внутри окна. Он использует структуру данныхdeque
, похожую на список, но оптимизированную для быстрых изменений (pop
,append
) на обеих конечных точках .Вот функция в действии:
источник
Немного опоздал на вечеринку, но я сделал свою маленькую функцию, которая НЕ обматывает концы или площадки нулями, которые затем используются для определения среднего значения. Еще одно преимущество заключается в том, что он также повторно дискретизирует сигнал в линейно разнесенных точках. Настройте код по желанию, чтобы получить другие функции.
Метод представляет собой простое матричное умножение с нормализованным ядром Гаусса.
Простое использование синусоидального сигнала с добавлением нормального распределенного шума:
источник
sum
, используяnp.sum
вместо 2 The@
оператора (понятия не имею , что это такое) выдает сообщение об ошибке. Я могу рассмотреть это позже, но мне не хватает времени прямо сейчас@
умножения матриц, который реализует np.matmul . Проверьте, является ли вашy_in
массив пустым, это может быть проблемой.Вместо того, чтобы болтать или скупиться, я бы порекомендовал пандам сделать это быстрее:
Для этого берется скользящее среднее (MA) из 3 периодов столбца «данные». Вы также можете рассчитать смещенные версии, например, ту, которая исключает текущую ячейку (смещенную на одну назад), можно легко вычислить как:
источник
pandas.rolling_mean
пока моеpandas.DataFrame.rolling
. Вы также можете легко рассчитать перемещениеmin(), max(), sum()
и т. Д., А такжеmean()
с этим методом.pandas.rolling_min, pandas.rolling_max
и т. Д. Они похожи, но отличаются.В одном из ответов выше есть комментарий от mab, в котором есть этот метод. имеет простое скользящее среднее:
bottleneck
move_mean
min_count
это удобный параметр, который в основном поднимает скользящее среднее до этой точки в вашем массиве. Если вы не установитеmin_count
, он будет равенwindow
, и все доwindow
очков будетnan
.источник
Еще один подход к поиску скользящей средней без использования numpy, панда
напечатает [2.0, 4.0, 6.0, 6.5, 7.4, 7.833333333333333]
источник
Этот вопрос теперь даже старше, чем когда NeXuS писал об этом в прошлом месяце, НО мне нравится, как его код обрабатывает крайние случаи. Однако, поскольку это «простая скользящая средняя», его результаты отстают от данных, к которым они применяются. Я думал, что работа с крайними случаями более удовлетворительна, чем режимы NumPy
valid
,same
иfull
может быть достигнута путем применения аналогичного подхода кconvolution()
основанному методу.Мой вклад использует центральное скользящее среднее, чтобы привести результаты в соответствие с их данными. Если для полноразмерного окна доступно слишком мало точек, средние значения вычисляются из последовательно меньших окон по краям массива. [На самом деле, из последовательно увеличивающихся окон, но это деталь реализации.]
Он сравнительно медленный, потому что он использует
convolve()
, и, вероятно, может быть подкреплен истинным Pythonista, однако, я считаю, что идея стоит.источник
Есть много ответов выше о вычислении среднего значения. Мой ответ добавляет две дополнительные функции:
Эта вторая особенность особенно полезна для определения того, какие значения отличаются от общей тенденции на определенную величину.
Я использую numpy.cumsum, так как это наиболее эффективный по времени метод ( см. Ответ Аллео выше ).
Этот код работает только для четных Ns. Его можно настроить для нечетных чисел, изменив np.insert из padded_x и n_nan.
Пример вывода (raw в черном, movavg в синем):
Этот код может быть легко адаптирован для удаления всех значений скользящих средних, рассчитанных из меньшего, чем значения отсечки = 3 не-нанона.
источник
Использовать только стандартную библиотеку Python (эффективная память)
Просто дайте другую версию использования только стандартной библиотеки
deque
. Для меня довольно удивительно, что большинство ответов используютpandas
илиnumpy
.На самом деле я нашел другую реализацию в документации Python
Однако реализация кажется мне более сложной, чем должна быть. Но по какой-то причине это должно быть в стандартных документах на Python, может кто-нибудь прокомментировать реализацию моей и стандартной документации?
источник
O(n*d)
вычисления ( будьd
то размер окна,n
размер повторяемого), и они делаютO(n)
С переменными @ Aikude я написал однострочник.
источник
Хотя здесь есть решения для этого вопроса, пожалуйста, посмотрите на мое решение. Это очень просто и работает хорошо.
источник
Прочитав другие ответы, я не думаю, что это то, о чем спрашивал вопрос, но я пришел сюда с необходимостью сохранять скользящее среднее значение списка значений, размер которого увеличивался.
Поэтому, если вы хотите сохранить список значений, которые вы получаете откуда-то (сайт, измерительное устройство и т. Д.) И среднее значение последних
n
обновленных значений, вы можете использовать приведенный ниже код, который минимизирует усилия по добавлению новых элементы:И вы можете проверить это, например:
Который дает:
источник
Другое решение, использующее стандартную библиотеку и deque:
источник
В образовательных целях позвольте мне добавить еще два решения Numpy (которые работают медленнее, чем решение cumsum):
Используемые функции: as_strided , add.reduceat
источник
Все вышеупомянутые решения плохие, потому что им не хватает
numpy.cumsum
илиO(len(x) * w)
реализаций в виде сверток.Дано
Обратите внимание, что
x_[:w].sum()
равноx[:w-1].sum()
. Таким образом , в первом среднемnumpy.cumsum(...)
добавляетx[w] / w
(черезx_[w+1] / w
), и вычитает0
(изx_[0] / w
). Это приводит кx[0:w].mean()
Через cumsum вы обновите второе среднее, дополнительно сложив
x[w+1] / w
и вычтяx[0] / w
, в результате чегоx[1:w+1].mean()
.Это продолжается до тех пор, пока не
x[-w:].mean()
будет достигнуто.Это решение векторизовано
O(m)
, читабельно и численно устойчиво.источник
Как насчет фильтра скользящей средней ? Он также является однострочным и имеет то преимущество, что вы можете легко манипулировать типом окна, если вам нужно что-то еще, кроме прямоугольника, т.е. N-длинная простая скользящая средняя массива a:
И с примененным треугольным окном:
Примечание: я обычно отбрасываю первые N сэмплов как фиктивные, следовательно,
[N:]
в конце, но это не является обязательным и является вопросом личного выбора.источник
Если вы решили использовать собственную библиотеку, а не использовать существующую библиотеку, помните об ошибке с плавающей запятой и постарайтесь свести к минимуму ее последствия:
Если все ваши значения примерно одинакового порядка, это поможет сохранить точность, всегда добавляя значения примерно одинаковых величин.
источник