- Как рассчитать скользящее среднее, используя NumPy?
- 6 ответов
- Moving Average for NumPy Array in Python
- Use the numpy.convolve Method to Calculate the Moving Average for NumPy Arrays
- Use the scipy.convolve Method to Calculate the Moving Average for NumPy Arrays
- Use the bottleneck Module to Calculate the Moving Average
- Use the pandas Module to Calculate the Moving Average
- Related Article — Python NumPy
Как рассчитать скользящее среднее, используя NumPy?
Разве скользящее среднее не является просто фильтром нижних частот (то есть «размытие»)? Уверен, это именно то, для чего предназначена свертка .
@wim Это было как бы каламбур. Но сам факт того, что вопрос существует, означает, что не просто создать скользящую среднюю из numpy.convolute.
Добавление np.convolve решения, которое в то время , возможно , не так эффективны , как и некоторые другие numpy решения, приятно иметь в качестве альтернативы для будущих посетителей , учитывая его простоту
6 ответов
Если вам просто нужна простая взвешенная скользящая средняя, вы можете легко реализовать ее с помощью np.cumsum , которая может быть быстрее, чем методы на основе FFT:
РЕДАКТИРОВАТЬ Исправлено неверное индексирование, указанное в коде Bean. ИЗМЕНИТЬ
def moving_average(a, n=3) : ret = np.cumsum(a, dtype=float) ret[n:] = ret[n:] - ret[:-n] return ret[n - 1:] / n >>> a = np.arange(20) >>> moving_average(a) array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., 17., 18.]) >>> moving_average(a, n=4) array([ 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5])
Итак, я думаю, что ответ таков: его действительно легко реализовать, и, возможно, numpy уже немного раздувается со специализированной функциональностью.
Это интересный способ сделать это, но, честно говоря, я бы не смог придумать это. Принадлежит ли он к NumPy, является спорным вопросом, но, конечно, Scipy может включить его?
Этот код неверен. например, moving_average ([1,2,5,10], n = 2) дает [1., 3.5, 8.5]. Даже тестовый пример ответчика для скользящего среднего значений от 0 до 19 неверен, утверждая, что среднее значение 0, 1 и 2 равно 0,5. Как он получил 6 голосов?
Спасибо за проверку ошибок, теперь, кажется, работает нормально. Что касается положительных отзывов, я предполагаю, что общая идея ответа была взвешена в большей степени, чем просто ошибочная реализация, но кто знает.
Это определенно не правильно, например, moving_average([1, 1, 1, 1, 1, 1], 2) дает [1, 1, 1, 1.5, 2] .
Я нашел проблему. ret[n:] -= ret[:-n] НЕ ТО ЖЕ, как ret[n:] = ret[n:] — ret[:-n] . Я исправил код в этом ответе. Редактировать: Нет, кто-то еще просто избил меня до этого.
@Timmmm Timmmm Я сделал, это было действительно проблемой. Общий принцип, лежащий в основе этого ответа, широко используется при обработке изображений (таблицы суммированных площадей, которые они называют), поэтому проблема должна быть в реализации. Хороший пример преждевременной оптимизации, так как я помню, как выполнял операцию на месте «потому что она будет более эффективной». С другой стороны, это, вероятно, дало неправильный ответ быстрее .
@askewchan В примере Timmmm при выполнении ret[2:] -= ret[:-2] ret равен [1, 2, 3, 4, 5, 6] . Когда он обрабатывает последнюю точку данных, он в основном выполняет ret[5] -= ret[3] . Мы хотели бы получить ret[5] = 6 — 4 , но вместо этого мы получаем ret[5] = 6 — 2 , потому что ret[3] уже был изменен операцией на месте, чтобы быть ret[3] -= ret[1] , то есть 2 . Если вы не выполняете операцию на месте, она создает временный массив и затем копирует его в ret , чтобы избежать этой проблемы.
Конечно, это имеет смысл. Так что ret[:-2] -= ret[2:] будет вести себя так же, как a[:-2] = a[:-2] — a[2:] так как выглядит вправо .
Что ж, есть проблема с тем, как numpy будет обращаться к памяти, и, боюсь, это деталь реализации. Кажется, имеет смысл, что память сканируется линейно в возрастающем порядке адресов, но я не уверен, что есть гарантия, что она не изменится в будущем. Для numpy 1.8 это верно, даже если вы берете вид с отрицательными шагами, т.е. если вы делаете ret = ret[::-1] перед выполнением вычитания на месте, он все равно ret[:-2] -= ret[2:] который дает правильный результат, но не ret[2:] -= ret[:-2] , что означает, что numpy обращается к памяти в порядке убывания адреса .
Нет, это не быстрее, может быть, это более удобно, но это медленнее, намного медленнее, если окно большое.
Что касается np.correlate(a, [0.25, 0.25, 0.25, 0.25]) , то это также распространяется на взвешенное скользящее среднее. np.correlate(a, [0.1, 0.2, 0.3, 0.4])
@Akavall Если вам нужна взвешенная скользящая средняя, то да, вероятно, correlate — это путь. Но поскольку correlate использует общий алгоритм, если ваше окно имеет размер m , в каждой точке оно должно выполнить m умножений и m-1 сложений. Метод здесь или то, что использует scipy.filter.uniform , требует только умножения, сложения и вычитания.
просто быстрый практический вопрос: какой конец моего вектора времени (время в секундах для каждого индекса) я хочу уменьшить после применения этого к сигнальному вектору? n = 3 удаляет 2 записи, n = 4 удаляет 3 и т. д. Моя интуиция заключается в том, что я должен удалить время из конца (правой стороны) вектора.
@user391339 user391339 Это зависит от того, что вы после. Если вы удалите время с конца, ваши записи будут усреднены в будущем. Если вы удалите время с начала, оно будет средним из прошлых значений. И вы можете даже удалить половину и половину, и иметь среднее по центру.
Хммм, кажется, что эту «простую в реализации» функцию на самом деле довольно легко ошибиться, и она привела к хорошему обсуждению эффективности памяти. Я счастлив, что раздули, если это означает, что я знаю, что что-то сделано правильно.
@Jaime. Я что-то упустил или вам нужна строка с ret[:n] /= np.arange(n) ? (Я уверен, что /= здесь хорошо, в отличие от -= раньше)
Для меня в python3 n = 3; x = np.arange(5); x[n:] -= x[:-n]; print(x) и n = 3; x = np.arange(5); x[n:] = x[n:] — x[:-n]; print(x) дает тот же результат [0 1 2 3 3] , зависит ли это от numpy версии?
Отсутствие отдельной функции, связанной с конкретным доменом, возможно, связано с дисциплиной и верностью основной команды в директиве NumPy prime: предоставить N-мерный тип массива, а также функции для создания и индексирования этих массивов. Как и многие основополагающие цели, этот не мал, и NumPy делает это блестяще.
(намного больше) SciPy содержит гораздо больший набор библиотек, специфичных для домена (называемых подпакетами для разработчиков SciPy) — например, численная оптимизация (оптимизация), процесс обработки сигналов (сигнал) и интегральное исчисление (интеграция).
Я предполагаю, что функция, по которой вы находитесь, находится, по крайней мере, в одном из подпакетов SciPy (возможно, scipy.signal); однако я бы посмотрел сначала в коллекции SciPy scikits, идентифицировал соответствующие scikit и искал интересующую функцию.
Scikits — это независимо разработанные пакеты на основе NumPy/SciPy и направленные на определенную техническую дисциплину (например, scikits-image, scikits- узнать и т.д.). Некоторые из них (в частности, удивительный OpenOpt для численной оптимизации) были высоко оценены, зрелые проекты задолго до выбора проживать под относительно новой рубрикой scikits. На домашней странице Scikits было написано около 30 таких сценариев, хотя по крайней мере некоторые из них больше не находятся в активной разработке.
Следуя этому совету, вы попадете в scikits-timeseries; однако этот пакет больше не находится в активной разработке; Фактически, Pandas стал AFAIK, фактической библиотекой временных рядов на основе NumPy.
Pandas имеет несколько функций, которые могут быть использованы для вычисления скользящей средней; самый простой из них, вероятно, roll_mean, который вы используете так:
>>> # the recommended syntax to import pandas >>> import pandas as PD >>> import numpy as NP >>> # prepare some fake data: >>> # the date-time indices: >>> t = PD.date_range('1/1/2010', '12/31/2012', freq='D') >>> # the data: >>> x = NP.arange(0, t.shape[0]) >>> # combine the data & index into a Pandas 'Series' object >>> D = PD.Series(x, t)
Теперь просто вызовите функцию roll_mean, проходящую в объекте Series, и размер окна, который в моем примере ниже 10 дней.
>>> d_mva = PD.rolling_mean(D, 10) >>> # d_mva is the same size as the original Series >>> d_mva.shape (1096,) >>> # though obviously the first w values are NaN where w is the window size >>> d_mva[:3] 2010-01-01 NaN 2010-01-02 NaN 2010-01-03 NaN
проверить, что это сработало — например, сравниваемые значения 10 — 15 в исходной серии по сравнению с новой серией, сглаженной скользящим средним
>>> D[10:15] 2010-01-11 2.041076 2010-01-12 2.041076 2010-01-13 2.720585 2010-01-14 2.720585 2010-01-15 3.656987 Freq: D >>> d_mva[10:20] 2010-01-11 3.131125 2010-01-12 3.035232 2010-01-13 2.923144 2010-01-14 2.811055 2010-01-15 2.785824 Freq: D
Функция roll_mean, а также около дюжины других функций неформально сгруппированы в документацию Pandas в разделе функций движущихся окон рубрики; вторая связанная группа функций в Pandas называется экспоненциально взвешенными функциями (например, ewma, которая вычисляет экспоненциально движущуюся средневзвешенную). Тот факт, что эта вторая группа не включена в первую (функции движущегося окна), возможно, потому, что экспоненциально взвешенные преобразования не полагаются на окно фиксированной длины
Moving Average for NumPy Array in Python
- Use the numpy.convolve Method to Calculate the Moving Average for NumPy Arrays
- Use the scipy.convolve Method to Calculate the Moving Average for NumPy Arrays
- Use the bottleneck Module to Calculate the Moving Average
- Use the pandas Module to Calculate the Moving Average
Moving average is frequently used in studying time-series data by calculating the mean of the data at specific intervals. It is used to smooth out some short-term fluctuations and study trends in the data. Simple Moving Averages are highly used while studying trends in stock prices.
Weighted moving average puts more emphasis on the recent data than the older data.
The graph below will give a better understanding of Moving Averages.
In this tutorial, we will discuss how to implement moving average for numpy arrays in Python.
Use the numpy.convolve Method to Calculate the Moving Average for NumPy Arrays
The convolve() function is used in signal processing and can return the linear convolution of two arrays. What is being done at each step is to take the inner product between the array of ones and the current window and take their sum.
The following code implements this in a user-defined function.
import numpy as np def moving_average(x, w): return np.convolve(x, np.ones(w), 'valid') / w data = np.array([10,5,8,9,15,22,26,11,15,16,18,7]) print(moving_average(data,4))
[ 8. 9.25 13.5 18. 18.5 18.5 17. 15. 14. ]
Use the scipy.convolve Method to Calculate the Moving Average for NumPy Arrays
We can also use the scipy.convolve() function in the same way. It is assumed to be a little faster. Another way of calculating the moving average using the numpy module is with the cumsum() function. It calculates the cumulative sum of the array. This is a very straightforward non-weighted method to calculate the Moving Average.
The following code returns the Moving Average using this function.
def moving_average(a, n) : ret = np.cumsum(a, dtype=float) ret[n:] = ret[n:] - ret[:-n] return ret[n - 1:] / n data = np.array([10,5,8,9,15,22,26,11,15,16,18,7]) print(moving_average(data,4))
[ 8. 9.25 13.5 18. 18.5 18.5 17. 15. 14. ]
Use the bottleneck Module to Calculate the Moving Average
The bottleneck module is a compilation of quick numpy methods. This module has the move_mean() function, which can return the Moving Average of some data.
import bottleneck as bn import numpy as np def rollavg_bottlneck(a,n): return bn.move_mean(a, window=n,min_count = None) data = np.array([10,5,8,9,15,22,26,11,15,16,18,7]) print(rollavg_bottlneck(data, 4))
[ nan nan nan 8. 9.25 13.5 18. 18.5 18.5 17. 15. 14. ]
Since the time window interval is 4, there are three nan values at the start because the Moving Average could not be calculated for them.
Use the pandas Module to Calculate the Moving Average
Time series data is mostly associated with a pandas DataFrame. Therefore the library is well equipped for performing different computations on such data.
We can calculate the Moving Average of a time series data using the rolling() and mean() functions as shown below.
import pandas as pd import numpy as np data = np.array([10,5,8,9,15,22,26,11,15,16,18,7]) d = pd.Series(data) print(d.rolling(4).mean())
0 NaN 1 NaN 2 NaN 3 8.00 4 9.25 5 13.50 6 18.00 7 18.50 8 18.50 9 17.00 10 15.00 11 14.00 dtype: float64
We first convert the numpy array to a time-series object and then use the rolling() function to perform the calculation on the rolling window and calculate the Moving Average using the mean() function.
Here also since, the time window interval is 4, there are three nan values at the start because the moving average could not be calculated for them.
Manav is a IT Professional who has a lot of experience as a core developer in many live projects. He is an avid learner who enjoys learning new things and sharing his findings whenever possible.