【问题标题】:Interpolate a Numpy array without using insert在不使用插入的情况下插入 Numpy 数组
【发布时间】:2018-08-16 23:41:13
【问题描述】:

所以我正在尝试做一些插值,我只是想知道我使用的代码是否可能更高效。

所以问题是这样的。我有一个值数组,其中包含来自许多不同站点的数据。它的尺寸为 N x 85,N 可能会因世界各地而异。

到目前为止,它们之间的时间间隔并不均匀。 0:51 列之间有 3 小时的 timedelta,然后 52:84 列之间有 6 小时的 timedelta。我只想在它们之间做一个简单的线性插值,以便所有行之间都有 3 小时的间距,所以基本上只是计算行之间的平均值 52:84 并将它们插入正确的位置.

这是一个小规模示例的快速代码示例,这是我目前正在做的,但效率不高(插入函数是我想避免的)。

import numpy as np
np.set_printoptions(linewidth=np.nan)

array = np.random.rand(5, 10) * 10
print(array)

interpolation_array = np.empty((5, 4))

for i, j in enumerate(list(range(5, 9))):
    interpolation_array[:, i] = np.mean(array[:, j:(j+2)], axis=1)
print(interpolation_array)

# This is the line that is not memory efficient
final_array = np.insert(array, list(range(6, 10)), interpolation_array, axis=1)

print(final_array)

【问题讨论】:

  • 如果你只做一个插入,我看不出有什么问题。您不能就地增长原始数组。
  • 如果不想使用insert,可以创建一个足够大的final_array,并将arrayinterpolation_array中的值复制到必要的槽中。跨度>
  • @hdpaulj 这就是我的想法,我只是想确保我没有错过可以让我加快速度的内置内容。谢谢

标签: python numpy memory-efficient


【解决方案1】:

所以正如@hpaulj 所建议的,我使用 Numba(LLVM 编译器比 Numpy 快)创建了一个大型矩阵来将所有值写入其中,然后使用并行循环来填充它并完成简单的实现线性插值。这是我使用的代码。

import numpy as np
from numba import jit, prange

@jit(nopython=True)
def numba_approach(array, c_start):  # c_start is column to start interpolating in (zero indexed)
    num_rows = array.shape[0]
    num_cols = array.shape[1]
    num_interp_columns = num_cols - 1 - c_start

    final_array = np.empty((num_rows, num_cols + num_interp_columns))

    # Populate the Portion That is not interpolated
    for i in prange(num_rows):
        for j in range(c_start + 1):
            final_array[i, j] = array[i, j]

    z = 1
    for j in prange(c_start + 2, num_cols + num_interp_columns, 2):
        for i in range(num_rows):
            final_array[i, j] = array[i, j - z]
        z += 1

    # Interpolate
    for j in prange(c_start + 1, num_cols + num_interp_columns - 1, 2):
        for i in range(num_rows):
            final_array[i, j] = (final_array[i, j - 1] + final_array[i, j + 1]) / 2

    return final_array

这给了我大约 4 倍的加速,这是相对显着的,因为这部分代码运行频繁。

基准测试:

%timeit numpy_approach(test_array)

100 loops, best of 3: 2.16 ms per loop

%timeit numba_approach(test_array, 47)

1000 loops, best of 3: 446 µs per loop

【讨论】:

    【解决方案2】:

    我认为正确的方法是使用适当的线性插值,例如numpy.interp。每个值的对应时间必须明确定义。这允许泛化到值之间的任何时间间隔。

    import numpy as np
    import matplotlib.pylab as plt
    
    times = [0, 3, 6, 9, 12, 18, 24, 30, 36]
    values = np.random.rand(len(times))
    
    times_regular = np.arange(0, times[-1]+1, 3)
    
    values_regular = np.interp(times_regular, times, values)
    
    plt.plot(times_regular, values_regular, 's', label='evently spaced');
    plt.plot(times, values, 'd-', label='measure');
    plt.xlabel('time'); plt.ylabel('value'); plt.legend();
    

    基于数组的解决方案,因为只需要中点,可能是:

    data_every6hr = np.array([[7, 5, 6, 9, 8, 5],
                              [7, 9, 6, 5, 6, 9],
                              [5, 6, 7, 9, 8, 8],
                              [5, 9, 8, 5, 7, 6]], dtype=float)
    
    # Perform the interpolation for every line
    intermediate_values = (data_every6hr[:, 1:] + data_every6hr[:, :-1])/2
    
    # Insert the interpolated values before each column:
    data_every3hr = np.insert(data_every6hr,
                              range(1, data_every6hr.shape[1]),
                              intermediate_values,
                              axis=1)
    
    print(data_every3hr)
    #array([[7. , 6. , 5. , 5.5, 6. , 7.5, 9. , 8.5, 8. , 6.5, 5. ],
    #       [7. , 8. , 9. , 7.5, 6. , 5.5, 5. , 5.5, 6. , 7.5, 9. ],
    #       [5. , 5.5, 6. , 6.5, 7. , 8. , 9. , 8.5, 8. , 8. , 8. ],
    #       [5. , 7. , 9. , 8.5, 8. , 6.5, 5. , 6. , 7. , 6.5, 6. ]])
    

    data_every6hr 只是输入数组中数据间隔 6 小时的部分。

    【讨论】:

    • 您运行基准测试了吗?如果这个实现比这更快,那很好,但我需要它是内存高效和快速的。这就是我刚刚使用平均值进行简单线性插值的原因。但总的来说,是的,我同意最好使用 numpy 提供的内置插值工具。
    • @xdze2 这个方法也可以在二维数组中插入行吗?
    • @Wade 我添加了另一个解决方案,我认为它更接近您的代码。您的应用程序中的N 有多大?
    • N 通常在 1500 左右,抱歉我忘了在原始问题中提及。我相信它可能会更大。
    猜你喜欢
    • 2019-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-21
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多