Python: 快速离散插值

5

给定一个表示离散坐标转换函数的4D数组,如下:

arr[x_in, y_in, z_in] = [x_out, y_out, z_out]

我想将arr插值到具有更多元素的网格上(假设arr中的样本最初是从高元素正方体的等间距网格中抽取的)。 我尝试了scipy中的RegularGridInterpolator,但速度比较慢:

import numpy as np
from scipy.interpolate import RegularGridInterpolator
from time import time

target_size   = 32
reduced_size  = 5

small_shape = (reduced_size,reduced_size,reduced_size,3)
cube_small  = np.random.randint(target_size, size=small_shape, dtype=np.uint8)

igrid = 3*[np.linspace(0, target_size-1, reduced_size)]
large_shape = (target_size, target_size, target_size,3)
cube_large  = np.empty(large_shape)

t0 = time()
interpol = RegularGridInterpolator(igrid, cube_small)
for x in np.arange(target_size):
    for y in np.arange(target_size):
        for z in np.arange(target_size):
            cube_large[x,y,z] = interpol([x,y,z])
print(time()-t0)

有没有什么算法能更适用于这个任务? 或许存在一些方法可以利用在这种情况下,我只对每个点的离散整数值感兴趣的事实。

2个回答

1

我无法确定你尝试做什么,所以无法确切地说出网格的生成方式。但是,仅就提高效率而言,使用三重循环而不是利用广播会极大地拖慢您的代码。

import itertools
import numpy as np
from scipy.interpolate import RegularGridInterpolator
from time import time

target_size   = 32
reduced_size  = 5

small_shape = (reduced_size,reduced_size,reduced_size,3)
cube_small  = np.random.randint(target_size, size=small_shape, dtype=np.uint8)


igrid = 3*[np.linspace(0, target_size-1, reduced_size)]


large_shape = (target_size, target_size, target_size,3)
cube_large  = np.empty(large_shape)

def original_method():
    t0 = time()

    interpol = RegularGridInterpolator(igrid, cube_small)
    for x in np.arange(target_size):
        for y in np.arange(target_size):
            for z in np.arange(target_size):
                cube_large[x,y,z] = interpol([x,y,z])

    print('ORIGINAL METHOD: ', time()-t0)
    return cube_large

def improved_method():
    t1 = time()
    interpol = RegularGridInterpolator(igrid, cube_small)

    arr = np.arange(target_size)
    grid = np.array(list(itertools.product(arr, repeat=3)))
    cube_large = interpol(grid).reshape(target_size, target_size, target_size, 3)

    print('IMPROVED METHOD:', time() - t1)

    return cube_large


c1 = original_method()
c2 = improved_method()

print('Is the result the same?  ', np.all(c1 == c2))

输出
ORIGINAL METHOD:  6.9040000438690186
IMPROVED METHOD: 0.026999950408935547
Is the result the same?   True

0

实际上,像Crivella建议的那样将整个网格传递似乎更加有效。我正在添加一个仅使用numpy的版本,它似乎比itertools快约2倍:

target_size = 256

... # Same as above

def do_new():
    t0 = time()
    grid = np.meshgrid(*3*[np.arange(target_size)], indexing='ij')
    grid = grid[::-1]
    grid = np.stack(grid).T
    ret  = interpol(grid)
    print(f"{time()-t0}")
    return ret

c1 = improved_method()
c2 = do_new()
print((c1==c2).all())

输出:

IMPROVED METHOD: 13.865211009979248
6.268443584442139
True

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接