Numpy - добавление массива с использованием предыдущего значения - PullRequest
0 голосов
/ 15 октября 2018

это то, как я должен что-то кодировать, где «минуты» и «поручения» - это списки одинакового размера (примеры ниже).

Но вместо этого это два пустых массива, поэтому этот код не работает.Другое дело, что я хотел бы, чтобы результат "done" также представлял собой пустой массив.

done = 0
for i in minute:
    if done < minute:
        done = minute + (errands * 2)
    else:
        done = done + (errands * 2)
    print (done)

Итак, я также попытался использовать "np.where"

import numpy as np
done = 0
done = np.where(done < minute, minute + (errands * 2), done + (errands * 2))
print(done)

Это было бы идеально, но проблема в том, что он не обновляет постоянно «done», чтобы в какой-то момент запускался эквивалентный код «done = done + (errands * 2)» (если это имеет смысл).

Несколько небольших примеров массива numpy:

minute = np.array([2, 2, 5, 5, 6, 7, 9, 11, 15])

errands = np.array([1, 1, 1, 7, 2, 2, 1, 1, 1])

Чтобы я мог быть максимально ясным, я хотел бы, чтобы результат "done" был

done = np.array([4, 6, 8, 22, 26, 30, 32, 34, 36])

Заранее спасибо за помощь.

Ответы [ 3 ]

0 голосов
/ 15 октября 2018

Это можно сделать только с помощью numpy:

def smart(m, e):
    e = 2*e
    r = np.empty(e.size+1, e.dtype)
    r[0] = 0
    e.cumsum(out=r[1:])
    return r[1:] + np.maximum.accumulate(m - r[:-1])

Тест и время: установить случайную задачу размером 1000:

>>> e = np.random.uniform(1, 3, 1000)
>>> m = np.random.uniform(1, 7, 1000).cumsum()

Дает тот же результат, что и numba:

>>> np.allclose(toggle(m, e), smart(m, e))
True

Но значительно быстрее, даже если исключено время компиляции:

>>> timeit(lambda: toggle(m, e))
21.466296120896004
>>> timeit(lambda: smart(m, e))
11.608282678993419
0 голосов
/ 16 октября 2018

Вы можете использовать Numba для очень эффективного выполнения этой задачи.

Но избегайте использования списков, когда это возможно, как @ user3483203 в своем ответе.Списки идут с очень большими накладными расходами, поскольку Numba не может напрямую работать со списками 2.6.2.4.1.Отражение списка

Пример

@nb.njit
def toggle_2(a, b):
    done=0.
    out=np.empty(a.shape[0],dtype=a.dtype)

    for i in range(a.shape[0]):
        if done < a[i]:
            done = a[i] + (b[i] * 2)
        else:
            done = done + (b[i] * 2)
        out[i]=done
    return out

Производительность

e = np.random.uniform(1, 3, 1_000)
m = np.random.uniform(1, 7, 1_000).cumsum()

Paul Panzer (smart) : 13.22 µs
user3483203 (toggle): 18.47 µs
toggle_2              2.47  µs

e = np.random.uniform(1, 3, 1_000_000)
m = np.random.uniform(1, 7, 1_000_000).cumsum()

Paul Panzer (smart) : 15.97 ms
user3483203 (toggle): 30.28 ms
toggle_2              3.77  ms
0 голосов
/ 15 октября 2018

Это итерационная проблема из-за обновления.Однако это O (n), и его можно эффективно использовать с помощью numba и njit:

Настройка

from numba import njit

Возможно, вам придется pip install numba


@njit
def toggle(a, b):
    done, out = 0, []    
    for i in range(len(a)):
        if done < a[i]:
            done = a[i] + (b[i] * 2)
        else:
            done = done + (b[i] * 2)
        out.append(done)
    return np.array(out)

toggle(minute, errands)

array([ 4,  6,  8, 22, 26, 30, 32, 34, 36], dtype=int64)

Производительность

minute = np.repeat(minute, 10000)
errands = np.repeat(errands, 10000)

%timeit toggle(minute, errands)
2.02 ms ± 9.84 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit toggle_no_njit(minute, errands)
64.4 ms ± 738 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...