【问题标题】:Downsample a 1D numpy array对一维 numpy 数组进行下采样
【发布时间】:2013-12-17 19:03:31
【问题描述】:

我有一个想要下采样的一维 numpy 数组。如果下采样栅格不能完全拟合数据,则可以使用以下任何一种方法:

  • 重叠下采样间隔
  • 将最后剩余的任意数量的值转换为单独的下采样值
  • 插值以适应栅格

基本上如果我有

1 2 6 2 1

并且我将采样率降低了 3 倍,以下所有情况都可以:

3 3

3 1.5

或者任何插值在这里给我的东西。

我只是在寻找最快/最简单的方法。

我找到了scipy.signal.decimate,但这听起来像是抽取这些值(根据需要取出它们,只在 X 中留下一个)。 scipy.signal.resample 似乎有正确的名称,但我不明白他们在描述中的整个傅里叶内容的去向。我的信号不是特别周期性。

你能帮我一下吗?这似乎是一项非常简单的任务,但所有这些功能都非常复杂......

【问题讨论】:

  • 你会推荐我怎么做
  • 我只会使用scipy.ndimage.zoom。不过,我确信它不会像 @shx2 的邻居那样快,但如果形状不能完美对齐,它会更易读且更易于使用。

标签: python numpy scipy signal-processing resampling


【解决方案1】:

在您的数组大小可被下采样因子 (R) 整除的简单情况下,您可以 reshape 您的数组,并沿新轴取平均值:

import numpy as np
a = np.array([1.,2,6,2,1,7])
R = 3
a.reshape(-1, R)
=> array([[ 1.,  2.,  6.],
         [ 2.,  1.,  7.]])

a.reshape(-1, R).mean(axis=1)
=> array([ 3.        ,  3.33333333])

在一般情况下,您可以使用NaNs 将数组填充到可被R 整除的大小,然后使用scipy.nanmean 取平均值。

import math, scipy
b = np.append(a, [ 4 ])
b.shape
=> (7,)
pad_size = math.ceil(float(b.size)/R)*R - b.size
b_padded = np.append(b, np.zeros(pad_size)*np.NaN)
b_padded.shape
=> (9,)
scipy.nanmean(b_padded.reshape(-1,R), axis=1)
=> array([ 3.        ,  3.33333333,  4.])

【讨论】:

    【解决方案2】:

    以下是一些使用线性插值或傅里叶方法的方法。这些方法支持上采样和下采样。

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.signal import resample
    from scipy.interpolate import interp1d
    
    def ResampleLinear1D(original, targetLen):
        original = np.array(original, dtype=np.float)
        index_arr = np.linspace(0, len(original)-1, num=targetLen, dtype=np.float)
        index_floor = np.array(index_arr, dtype=np.int) #Round down
        index_ceil = index_floor + 1
        index_rem = index_arr - index_floor #Remain
    
        val1 = original[index_floor]
        val2 = original[index_ceil % len(original)]
        interp = val1 * (1.0-index_rem) + val2 * index_rem
        assert(len(interp) == targetLen)
        return interp
    
    if __name__=="__main__":
    
        original = np.sin(np.arange(256)/10.0)
        targetLen = 100
    
        # Method 1: Use scipy interp1d (linear interpolation)
        # This is the simplest conceptually as it just uses linear interpolation. Scipy
        # also offers a range of other interpolation methods.
        f = interp1d(np.arange(256), original, 'linear')
        plt.plot(np.apply_along_axis(f, 0, np.linspace(0, 255, num=targetLen)))
    
        # Method 2: Use numpy to do linear interpolation
        # If you don't have scipy, you can do it in numpy with the above function
        plt.plot(ResampleLinear1D(original, targetLen))
    
        # Method 3: Use scipy's resample
        # Converts the signal to frequency space (Fourier method), then back. This
        # works efficiently on periodic functions but poorly on non-periodic functions.
        plt.plot(resample(original, targetLen))
    
        plt.show()
    

    【讨论】:

    【解决方案3】:

    如果数组大小不能被下采样因子 (R) 整除,则可以使用 np.linspace 后跟每个子数组的平均值来对数组进行整形(拆分)。

    input_arr = np.arange(531)
    
    R = 150 (number of split)
    
    split_arr = np.linspace(0, len(input_arr), num=R+1, dtype=int)
    
    dwnsmpl_subarr = np.split(input_arr, split_arr[1:])
    
    dwnsmpl_arr = np.array( list( np.mean(item) for item in dwnsmpl_subarr[:-1] ) )
    

    【讨论】:

    • 一般来说,如果答案包含对代码的用途的解释,以及为什么在不介绍其他人的情况下解决问题的原因,答案会更有帮助。
    猜你喜欢
    • 2019-04-17
    • 2013-04-20
    • 2021-11-24
    • 2015-10-27
    • 2012-06-06
    • 2017-06-12
    • 1970-01-01
    • 2019-10-27
    • 1970-01-01
    相关资源
    最近更新 更多