Неполная сумма столбца матрицы или вложенного списка - PullRequest
2 голосов
/ 13 февраля 2020

Код, приведенный ниже, является попыткой получить матрицу с частичной суммой столбца другого, так что строки row[r] результирующей матрицы являются частичной суммой столбца исходной матрицы из row=0 к row=r.

Например, учитывая

A = [[0,0,0],
     [4,5,6],
     [7,8,9],
     [10,11,12]]

Я хотел бы получить

B=[[0,0,0],
   [4,5,6],
   [11,13,15],
   [21,24,27]]
  1. Есть ли альтернатива, которая позволяет мне исключить for-l oop в следующем коде и который позволяет мне вместо этого использовать чистое списочное понимание?

  2. Считаете ли вы, что списочное понимание будет более вычислительно эффективным, чем for-loop или map / lambda при условии, что фактические матрицы, над которыми я работаю, относительно большие?

Мой текущий код приведен ниже:

import numpy as np
# Define matrices M and S
M= np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
H = np.array([0.1, 0.2, 0.3])
# Define matrix S with: S[0] = [0,0,0,0] and S[r>0][c] = M[r][c]xH[r]
S = np.array([[x if r != 0 else 0 for x in [M[r][c] * H[r] for c in range(0, len(M[r]))]] for r in range(len(M))])
# initialize matrix L
L = np.array(np.zeros((int(len(M)),int(len(M[0])))))
#Update Matrix L: L[r][c] = Sum[S[0][c] to S[i=r-1][c]]
for r in range(0, len(L)):
        L[r] = [sum([row[i] for row in S[0:r+1]]) for i in range(0,len(S[0]))]
print("S", S)
print("L", L)

1 Ответ

1 голос
/ 14 февраля 2020

При использовании numpy самый быстрый способ сделать что-либо - обычно использовать трансляцию или векторизацию. Вы можете прочитать больше об этом здесь , но в основном это означает применение функции к массиву данных одновременно, а не итерацию по массиву с использованием for-l oop.

Возможно, это было то, на что вы ссылались, когда говорили о понимании списков, но в глубине души это просто другой способ написания циклов for.

Функция, которую вы ищете в этом case равен np.cumsum(), используя axis=0, чтобы указать, что мы хотим суммировать по каждому столбцу. Это векторизованный метод применения логи c, который вы ищете, и он будет намного быстрее, чем ваше решение for-l oop на больших матрицах.

>>> A = np.array([[0,0,0],[4,5,6],[7,8,9],[10,11,12]])
>>> np.cumsum(A, axis=0)
array([[ 0,  0,  0],
       [ 4,  5,  6],
       [11, 13, 15],
       [21, 24, 27]], dtype=int32)

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

enter image description here

Код для генерации:

import perfplot
import numpy as np

def cdjb_cumsum(A):
    return np.cumsum(A, axis=0)

def ajbg_forloop(A):
    L = np.array(np.zeros((int(len(A)),int(len(A[0])))))
    for r in range(0, len(L)):
        L[r] = [sum([row[i] for row in A[0:r+1]]) for i in range(0,len(A[0]))]
    return L

perfplot.show(
    setup=lambda n: np.random.rand(n, n),
    n_range=[2**k for k in range(20)],
    kernels=[
        cdjb_cumsum, ajbg_forloop
        ],
    xlabel='Size of Array (n*n)',
    )
...