Превратите цикл for по массиву NumPy в срез

#python #arrays #numpy

Вопрос:

У меня есть этот цикл для вычисления элементов 3D-массива numpy:

 A = np.zeros((N - 2, N - 2, N - 2)) for i in range(1, N - 1):  for j in range(1, N - 1):  for k in range(1, N - 1):  A[i - 1, j - 1, k - 1] = (B[i,j,k] * dy[j] * dz[k]   B[i,j-1,k] * dy[j-1] * dz[k]    B[i,j,k-1] * dy[j] * dz[k-1]   B[i,j-1,k-1] * dy[j-1] * dz[k-1]) / (4 * dx[i])  

Где B-массив numpy формы (N, N, N), а dx, dy и dz-массивы numpy длины N-1. Для больших N это действительно медленно, поэтому я попробовал что-то вроде этого:

 A = (B[1:-1, 1:-1, 1:-1] * dy[1:] * dz[1:]   B[1:-1, :-2, 1:-1] * dy[:-1] * dz[1:]    B[1:-1, 1:-1, :-2] * dy[1:] * dz[:-1]   B[1:-1, :-2, :-2] * dy[:-1] * dz[:-1]) / (4 * dx[1:])  

Это не работает, если dx, dy и dz не являются постоянными. Я тоже пытался:

 dX, dY, dZ = np.meshgrid(dx, dy, dz) A = (B[1:-1, 1:-1, 1:-1] * dY[1:, 1:, 1:] * dZ[1:, 1:, 1:]   B[1:-1, :-2, 1:-1] * dY[:-1, :-1, :-1] * dZ[1:, 1:, 1:]    B[1:-1, 1:-1, :-2] * dY[1:, 1:, 1:] * dZ[:-1, :-1, :-1]   B[1:-1, :-2, :-2] * dY[:-1, :-1, :-1] * dZ[:-1, :-1, :-1]) / (4 * dX[:-1, :-1, :-1])  

Но и это тоже не работает.

Есть какие-нибудь идеи о том, как это сделать?

Комментарии:

1. Можете ли вы опубликовать некоторые примеры данных в быстро воспроизводимом примере?

2. Фактические данные немного сложны. Но любые B, dx, dy и dz правильной формы должны работать. Я не могу легко предоставить данные через комментарий, потому что в B уже есть N^3 элементов.

3. Любой пример или добавленный может быть добавлен в вопрос с помощью редактирования. Комментарии не очень хорошо форматируют подобные вещи. Но нам не нужны реальные данные; нам нужен пример, где N мало. Например, один такой, который A по крайней мере (2,2,2). Кроме того, вместо того, чтобы говорить «не работает», покажите ошибку, а еще лучше, приложите некоторые усилия для понимания и исправления ошибки.

4. Он должен работать для любых данных правильной формы, как я уже сказал, поэтому данные, которые я на самом деле использую, не должны иметь значения или быть необходимыми для его работы. Но если вам действительно нужна конкретика, вы можете сказать N = 5,B = np.random.rand(N,N, N) и dx=dy=dz = [0.5857864376269049, 0.41421356237309515, 0.41421356237309515, 0.5857864376269049]. Также я не могу показать ошибку, потому что ошибки нет, цифры просто неправильные. Я также показал вам два отдельных способа, которыми я пытался решить эту проблему, я не знаю, как вы можете сказать, что я не приложил усилий, пытаясь понять это.

Ответ №1:

 A[i - 1, j - 1, k - 1] = (B[i,j,k] * dy[j] * dz[k]   B[i,j-1,k] * dy[j-1] * dz[k]    B[i,j,k-1] * dy[j] * dz[k-1]   B[i,j-1,k-1] * dy[j-1] * dz[k-1]) / (4 * dx[i])  

давайте изменим итерации на (0,N-2)

 A[i, j, k] = (B[i 1,j 1,k 1] * dy[j 1] * dz[k 1]   B[i 1,j,k 1] * dy[j] * dz[k 1]    B[i 1,j 1,k] * dy[j 1] * dz[k]   B[i 1,j,k] * dy[j] * dz[k]) / (4 * dx[i 1])  

и рассмотрите 4 условия отдельно

 B[1:,1:,1:]*dy[None,1:,None]*dz[None,None,1:]  B[1:,:-1,1:]*dy[None,:-1,None]*dz[None,None,1:]  etc  

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

Комментарии:

1. Спасибо. Я использовал B[1:-1,1:-1,1:-1]*dy[Нет,1:,Нет]*dz[Нет,нет,1:] … и это работает сейчас. Экономит много времени по сравнению с 3 вложенными циклами