У меня есть массив трехмерных координат M x 3, координаты (M ~ 1000-10000), и я хотел бы вычислить сумму гауссиан с центром в этих координатах в трехмерном массиве сетки сетки. Трехмерный массив ячеистой сетки, как правило, имеет размер 64 x 64 x 64, но иногда может быть больше 256 x 256 x 256 и может увеличиваться. Для начала я следовал этому вопросу , преобразовав свой массив meshgrid в массив координат N x 3, xyz , где N равно 64 ^ 3 или 256 ^ 3 и т. Д. Однако для больших размеров массива требуется слишком много памяти, чтобы векторизовать весь расчет (понятно, так как он может приблизиться к элементам 1e11 и потреблять терабайт ОЗУ), поэтому я разбил его на цикл по М координатам. Однако это слишком медленно.
Мне интересно, есть ли способ ускорить это вообще без перегрузки памяти. Преобразуя сетку сетки в xyz, я чувствую, что потерял какое-либо преимущество равномерного расположения сетки, и что каким-то образом, может быть, с помощью scipy.ndimage, я смогу воспользоваться преимуществами равномерного расстояния, чтобы ускорить процесс.
Вот мой начальный старт:
import numpy as np
from scipy import spatial
#create meshgrid
side = 100.
n = 64 #could be 256 or larger
x_ = np.linspace(-side/2,side/2,n)
x,y,z = np.meshgrid(x_,x_,x_,indexing='ij')
#convert meshgrid to list of coordinates
xyz = np.column_stack((x.ravel(),y.ravel(),z.ravel()))
#create some coordinates
coords = np.random.random(size=(1000,3))*side - side/2
def sumofgauss(coords,xyz,sigma):
"""Simple isotropic gaussian sum at coordinate locations."""
n = int(round(xyz.shape[0]**(1/3.))) #get n samples for reshaping to 3D later
#this version overloads memory
#dist = spatial.distance.cdist(coords, xyz)
#dist *= dist
#values = 1./np.sqrt(2*np.pi*sigma**2) * np.exp(-dist/(2*sigma**2))
#values = np.sum(values,axis=0)
#run cdist in a loop over coords to avoid overloading memory
values = np.zeros((xyz.shape[0]))
for i in range(coords.shape[0]):
dist = spatial.distance.cdist(coords[None,i], xyz)
dist *= dist
values += 1./np.sqrt(2*np.pi*sigma**2) * np.exp(-dist[0]/(2*sigma**2))
return values.reshape(n,n,n)
image = sumofgauss(coords,xyz,1.0)
import matplotlib.pyplot as plt
plt.imshow(image[n/2]) #show a slice
plt.show()
М = 1000, N = 64 (~ 5 секунд):
М = 1000, N = 256 (~ 10 минут):