Понимание списка с вложенными l oop, условными и аккумуляторными - PullRequest
2 голосов
/ 06 августа 2020

Я пытаюсь преобразовать этот фрагмент кода в понимание списка:

a = np.random.rand(10) #input vector
n = len(a) # element count of input vector
b = np.random.rand(3) #coefficient vector
nb = len(b) #element count of coefficients
d = nb #decimation factor (could be any integer < len(a))
 
c = []
for i in range(0, n, d):
    psum = 0
    for j in range(nb):
        if i + j < n:
            psum += a[i + j]*b[j]
    c.append(psum)

Я пробовал следующие предложения:

Например:

from itertools import accumulate
c = [accumulate([a[i + j] * b[j] for j in range(nb) if i + j < n] ) for i in range(0, n, d)]

Позже , при попытке получить значения из c (например, c[:index]):

TypeError: 'NoneType' object is not subscriptable

Или:

from functools import partial
def get_val(a, b, i, j, n):
    if i + j < n:
        return(a[i + j] * b[j])
    else:
        return(0)
c = [
         list(map(partial(get_val, i=i, j=j, n=n), a, b)) 
             for i in range(0, n, d) 
             for j in range(nb)
    ]

in get_val, return (a [i + j] * b [j])

IndexError: invalid index to scalar variable.

Или:

psum_pieces = [[a[i + j] * b[j] if i + j < n else 0 for j in range(nb)] for i in range(0, n, d)]
c = [sum(psum) for psum in psum_pieces]

Как и многие другие итерации этих подходов. Будем очень признательны за любые рекомендации.

Ответы [ 2 ]

1 голос
/ 06 августа 2020

Вам действительно не нужно использовать здесь понимание списка. С помощью numpy вы можете создать быстрое конвейерное решение, которое не запускает никаких циклов непосредственно в интерпретаторе.

Сначала преобразуйте a в 2D-массив в форме (n // d, nb). Отсутствующие элементы (т.е. где i + j >= n в l oop) могут быть равны нулю, поскольку это приведет к соответствующему приращению до psum нуля:

# pre-compute i+j as a 2D array
indices = np.arange(nb) + np.arange(0, n, d)[:, None]
# we only want valid locations
mask = indices < n

t = np.zeros(indices.shape)
t[mask] = a[indices[mask]]

Теперь вы можете вычислить c напрямую as

(t * b).sum(axis=1)

Я подозреваю, что если вы сравните это решение с чем-либо, написанным в vanilla python, не скомпилированным с помощью numba, оно будет намного быстрее.

1 голос
/ 06 августа 2020

Если я правильно понял, что вам нужно, это что-то вроде

res = [sum(a[i+j]*b[j] for j in range(nb) if i+j < n) for i in range(0,n,d)]

Для каждого i это добавит к итоговому списку сумму продуктов a[i+j]*b[j] для j, которые изменяется от 0 до nb-1, когда i+j < n

...