Я хотел бы использовать Numberxpr для вычисления 2D-массива в виде суммы по одной оси 3D-массива. Трехмерный массив достаточно велик, чтобы его невозможно было сохранить в памяти.
Самый простой подход - использовать сокращение NumberxPR, но это довольно медленно.
import numpy as np
import numexpr as ne
numx = 1e3
xaxis = np.arange(numx) * 10 / numx
dx = xaxis[:, None] - xaxis[None, :]
qrange = np.arange(0, 20)
# naive ne implimentations
qb = qrange[None, None, :]
dxb = dx[:, :, None]
tes = "sum(1j * exp(1j * qb * dxb), axis=2)"
Gf1 = ne.evaluate(tes)
Производительность можно улучшить, выполнив сумму вне числаxpr. Это сталкивается с проблемой хранения промежуточного трехмерного массива. Вместо того, чтобы вычислять все это, необходимо выполнять вычисления итеративно небольшими порциями.
# avoid sum in ne, but chunk calculation to be gentle on memory
nq = 10
nes = "1j * exp(1j * qx * dxb)"
num_chunks = int(np.ceil(qrange.size / nq))
ier = np.array_split(np.arange(qrange.size), num_chunks, axis=-1)
Gf2 = np.zeros(dx.shape, dtype=np.complex)
for ix in ier:
qx = qb[:, :, ix]
temp = ne.evaluate(nes)
temp = np.sum(temp, axis=-1)
Gf2 += temp
Итеративный метод повышает производительность, но требует выполнения операций в numpy, что не так быстро, как цифра. Можно выполнить все вычисления в виде длинного явного выражения, динамически генерируя строку оценки.
# generate sum as a long string
template = np.array("1j * exp( 1j * qx * dx )".split(" "))
delt_vars = {}
bes = ""
for i, _ in enumerate(qrange):
delt_vars['qn'+str(i)] = q
temp = template.copy()
temp[temp == 'qx'] = 'qn' + str(i)
bes += '+' + ''.join(temp.tolist())
Gf3 = ne.evaluate(bes, local_dict=delt_vars)
В этом примере явное выражение для Gf3
обеспечивает наилучшую производительность. Однако переход к более сложным выражениям наталкивается на неожиданное ограничение числаxpr. Более длинные выражения ( т.е. qrange = np.arange(0, 100)
) вызывают одну из двух ошибок:
ValueError: bytes must be in range(0, 256)
или ValueError: too many inputs
Вторая ошибка, по-видимому, связана с ограничение numpy, обсуждаемое в: Pytables NumExpr ValueError: слишком много входных данных при запросах с большим количеством условий
Можно ли улучшить производительность сложных сокращений в Numberxpr с помощью long и явные строки оценки? Если нет, то есть ли лучший способ выполнить вычисления такого типа, которые сохранят производительность NumberxPR?