Возможно ли сгенерировать процесс AR(1) без циклов?

#python #numpy

Вопрос:

Можно ли превратить следующий цикл кода Python в код без циклов в Python?

 steps = 10000
rho = 0.9

e = np.random.randn(steps)
y = [0]

# Possible to get rid of this loop?
for i in range(len(e)):
    y.append(rho*y[i]   e[i])
 

Код предназначен для генерации простых авторегрессионных (порядка 1) временных рядов, где при заданном некотором начальном значении каждое следующее значение соответствует предыдущему времени плюс некоторый случайный шум.

https://en.wikipedia.org/wiki/Autoregressive_model

Комментарии:

1. Я не понимаю. В чем конкретно заключается возражение против цикла (чтобы я знал, что приемлемо) ? На что ты надеешься?

2. @MarkSetchell проверьте мой код. @NeverStopLearning пытается создать программу такого типа без цикла, что можно сделать с помощью iterator

3. @MarkSetchell, numpy тег предполагает, что OP хочет быстрого numpy решения, которое использует свои скомпилированные методы всего массива. Для последовательных операций, подобных этой, это может быть сложно. numpy лучше всего, когда операция применяется ко всему массиву без каких-либо подразумеваемых последовательных действий.

4. Изменение e на e = e.tolist() ускорение кода, так как индексирование отдельных элементов списка происходит быстрее.

5. @NeverStopLearning, …но что считается «без цикла»? Если вы вызываете функцию, и у этой функции есть цикл, это считается? Если вы используете синтаксис, который неявно зацикливается, это считается? Где именно находится граница того, что является и не является петлей для целей этого вопроса?

Ответ №1:

Проверьте этот код :

 import numpy as np

steps = 10000
rho = 0.9
np.random.seed(0)
e = np.random.randn(steps)

z = list(np.zeros(steps))
z[:] = map(lambda x, y: rho*z[y]   x, list(e), list(range(steps)))
 

Способ-2 :

 m = list(np.zeros(steps))
m[:] = map(lambda x, y: m.append(rho*m[y]   x), list(e), list(range(steps)))
m = m[10000:]
print(m)
 

Несколько быстрых тестов от ipython

 In [1]: timeit z[:] = map(lambda x, y: rho*z[y]   x, list(e), list(range(steps)))
1.27 ms ± 19.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [2]: timeit m[:] = map(lambda x, y: m.append(rho*m[y]   x), list(e), list(range(steps)))
1.39 ms ± 31.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [3]: timeit for i in range(len(e)): y.append(rho*y[i]   e[i])
8.18 ms ± 270 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
 

Комментарии:

1. Ваши map тайминги должны включать эту z[:] часть. map это просто упрощенный способ выполнения цикла Python. Я не думаю, что это то, о чем просит операция.

2. Я не думаю, что это повторяет операцию. Ваш z имеет те же ценности, e что и .