SciPy:在三维网格上插入分散的数据



我的数据是随机间隔的(x,y,z,d(,我需要在3D网格上插值。问题是网格相当大:点的总数是nx*ny*nz = 345*188*1501 = 97 354 860

我试图使用Rbf插值同时通过所有点,但我得到了错误:

numpy.core._exceptions._ArrayMemoryError: Unable to allocate 343. GiB for an array with shape (97354860, 473) and data type float64(这里473是什么?(

作为我尝试的一个例子:

from scipy.interpolate import Rbf
rng = np.random.default_rng()
x, y, z, d = rng.random((4, 50))
rbfi = Rbf(x, y, z, d)
# xi, yi, zi alltogether take about 3 Gb
xi = yi = zi = np.linspace(0, 1, 97354860)
di = rbfi(xi, yi, zi)  # here I get error

但后来我尝试在循环中逐点插值,它似乎工作得足够慢(插值大约需要20分钟(:

for i in range(0, xi.shape[0]):
di[i] = rbfi(xi[i], yi[i], zi[i])

那么问题来了:在循环中插值和同时插值所有点之间有什么区别?我认为Rbf应该使用循环在每个请求点(xi,yi,zi(上对输入数据点进行内部插值。

我还认为,如果我一次通过所有点,或者逐点插值,插值结果应该不会有差异。

正如您所提到的,当您使用NumPy时,您同时处理所有数据卷,这将受到系统ram大小的限制。但是,当您使用循环时,由于迭代和直接分配,该工作负载不会应用于ram。在这方面,我认为使用chunks可以非常有效;即用Chunks将总尺寸划分为某些部分。然后,您可以通过在部件上循环并传递ram限制来使用数组。因此,提议的方式将类似于:

chunk_val = 2000000                  # it is arbitrary and must be choosed based on the system rams size 
chunk = xi.shape[0] // chunk_val
chunk_res = xi.shape[0] % chunk_val
# by array
di = np.array([])
start = 0
for i in range(chunk + 1):
di = np.append(di, rbfi(xi[start:(i+1) * chunk_val], yi[start:(i+1) * chunk_val], zi[start:(i+1) * chunk_val]))
start += chunk_val
if i == chunk:
di = np.append(di, rbfi(xi[start:xi.shape[0]], yi[start:xi.shape[0]], zi[start:xi.shape[0]]))
# by list
di = []
start = 0
for i in range(chunk + 1):
di.append(rbfi(xi[start:(i+1) * chunk_val], yi[start:(i+1) * chunk_val], zi[start:(i+1) * chunk_val]))
start += chunk_val
if i == chunk:
di.append(rbfi(xi[start:xi.shape[0]], yi[start:xi.shape[0]], zi[start:xi.shape[0]]))
di = [item for sublist in di for item in sublist]

在上述代码中,提出了两种方法,一种是通过数组,另一种是根据列表。我已经在性能方面测试了这种方法,它在Google Collaborative上使用了70 s
如果Numba与rbfidtype兼容,它也可以由Numba处理。如果是这样,它可能是最快的方法之一,必须进行评估。

更新:


我认为唯一的方法是使用块。正如您在rbf源代码中所看到的,rbf相关类中有一系列函数将被运行,它们的数据必须存储在系统中的某个位置(ram(,直到所有函数都完成为止(您可以使用pprofiler和…等评测器评测rbf的每一行,以查看源代码的哪一部分消耗最多时间、ram或…(。因此,AFAIK,当您在迭代中导入数据时,函数在较小的数据量上运行(可以由系统硬件处理(,并且创建的临时数组和…将在每个循环中释放或覆盖。因此,迭代不会导致内存泄漏或…。