Использование генераторов для заполнения / создания массива numpy без циклов for - PullRequest
0 голосов
/ 02 мая 2020

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

Я sh использую numpy array для сохранения данных из генератора (который возвращает кортеж с time, position, velocity, acceleration). Для выполнения sh того, что я ранее создал массив numpy и в a для l oop (с перечислением), я заполняю все местоположения.

У меня вопрос, есть ли способ избежать for loop вообще?

Код идет ниже.

import numpy as np

def random_walk(initial_position = 0, accel = 0, pa=0.25, pb=.5):
    """Initial position (often 0), acceleration, 0 < pa < pb < 1"""
    # Time, x-position, Velocity, Acceleration
    t, x, v, a = 0, initial_position, 0, accel
    yield (t, x, v, a)

    while True:        
        # Roll the dices
        god_wishes = np.random.random()

        if god_wishes <= pa:
                # Increase acceleration
                a += .1
        elif god_wishes <= pb:
                # Reduce acceleration
                a -= .1

        # Lets avoid too much acceleration
        a = np.clip(a, -.5, +.5)

        # How much time has passed, since last update?
        dt = np.random.random()
        v += dt*a
        x += dt*v
        t += dt

        yield (t, x, v, a)

Затем я создаю симуляцию с

rw = random_walk(0, .2, .25, .5)

И я запускаю эксперимент

experiment = np.zeros((1000,4))
for i in range(1000):
    experiment[i] = rw.__next__()

То есть for l oop, которого я ДЕЙСТВИТЕЛЬНО хочу избежать. Приветствуется эффективный подход.

Есть подсказки?

1 Ответ

0 голосов
/ 02 мая 2020

Вы можете значительно ускорить генератор random_walk на , а не , используя np.clip.

Этот тест демонстрирует ускорение:

import numpy as np

def clip(value, lower, upper):
    return lower if value < lower else upper if value > upper else value

def random_walk(initial_position = 0, accel = 0, pa=0.25, pb=.5, clip_function=np.clip):
    """Initial position (often 0), acceleration, 0 < pa < pb < 1"""
    # Time, x-position, Velocity, Acceleration
    t, x, v, a = 0, initial_position, 0, accel

    yield (t, x, v, a)

    while True:
        # # Roll the dices
        god_wishes = np.random.random()

        if god_wishes <= pa:
                # Increase acceleration
                a += .1
        elif god_wishes <= pb:
                # Reduce acceleration
                a -= .1

        # # Lets avoid too much acceleration
        a = clip_function(a, -.5, +.5)

        # # How much time has passed, since last update?
        dt = np.random.random()
        v += dt*a
        x += dt*v
        t += dt

        yield (t, x, v, a)

from timeit import timeit

def f1():
    rw = random_walk(0, .2, .25, .5)
    experiment = np.zeros((1000,4))
    for i in range(1000):
        experiment[i] = rw.__next__()
    return experiment

def f2():
    rw = random_walk(0, .2, .25, .5, clip_function=clip)
    return np.array([next(rw) for _ in range(1000)])

t1 = timeit(lambda: f1(), number=10)
t2 = timeit(lambda: f2(), number=10)

print(t1)
print(t2)

Печать на моей машине (2400G драм, numPy 1.18.3):

0.26705767000385094
0.01964799000415951
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...