【问题标题】:Stretch an array and fill nan拉伸一个数组并填充 nan
【发布时间】:2019-06-15 16:09:46
【问题描述】:

我有一个长度为 n 的一维 numpy 数组,我想将它拉伸到 m (n

例如:

>>> arr = [4,5,1,2,6,8] # take this
>>> stretch(arr,8)
[4,5,np.nan,1,2,np.nan,6,8] # convert to this

要求: 1.两端没有nan(如果可能) 2. 全力以赴

我试过了

>>> def stretch(x,to,fill=np.nan):
...     step = to/len(x)
...     output = np.repeat(fill,to)
...     foreign = np.arange(0,to,step).round().astype(int)
...     output[foreign] = x
...     return output

>>> arr = np.random.rand(6553)
>>> stretch(arr,6622)

  File "<ipython-input-216-0202bc39278e>", line 2, in <module>
    stretch(arr,6622)

  File "<ipython-input-211-177ee8bc10a7>", line 9, in stretch
    output[foreign] = x

ValueError: shape mismatch: value array of shape (6553,) could not be broadcast to indexing result of shape (6554,)

似乎不能正常工作(对于一个长度为 6553 的数组,违反 req 2,并且不保证 1),有什么线索可以克服这个问题吗?

【问题讨论】:

  • 添加 NaN 背后的逻辑是什么?他们是如何定位的?
  • “系统地”解释它,换句话说,均匀分布(尽可能)。我将以各种方式处理 NaN,这与这个问题无关。

标签: python arrays numpy nan numpy-ndarray


【解决方案1】:

使用roundrobin from itertools Recipes:

from itertools import cycle, islice

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    pending = len(iterables)
    nexts = cycle(iter(it).__next__ for it in iterables)
    while pending:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            pending -= 1
            nexts = cycle(islice(nexts, pending))

def stretch(x, to, fill=np.nan):
    n_gaps = to - len(x)
    return np.hstack([*roundrobin(np.array_split(x, n_gaps+1), np.repeat(fill, n_gaps))])

arr = [4,5,1,2,6,8]
stretch(arr, 8)
# array([ 4.,  5., nan,  1.,  2., nan,  6.,  8.])

arr2 = np.random.rand(655)
stretched_arr2 = stretch(arr,662)
np.diff(np.argwhere(np.isnan(stretched_arr2)), axis=0)
# nans are evenly spaced    
array([[83],
       [83],
       [83],
       [83],
       [83],
       [83]])

背后的逻辑

n_gaps: 计算要填充多少间隙(期望长度 - 当前长度)

np_array_split: 使用n_gaps+1,它将输入数组拆分为尽可能相同的长度

roundrobin:由于np_array_split 生成的数组比间隙多一个,循环(即交替迭代)允许np.nan 永远不会出现在结果的任何一端。

【讨论】:

    【解决方案2】:

    这种方法将非 nan 元素放置在边界处,将 nan 值留在中心,尽管它不会均匀地分隔 nan 值。

    arr = [4,5,1,2,6,8]   
    stretch_len = 8    
    
    def stretch(arr, stretch_len):
        stretched_arr = np.empty(stretch_len)   
        stretched_arr.fill(np.nan)
        arr_len = len(arr)
    
        if arr_len % 2 == 0:
            mid = int(arr_len/2)
            stretched_arr[:mid] = arr[:mid]
            stretched_arr[-mid:] = arr[-mid:]
        else:
            mid = int(np.floor(arr_len/2))
            stretched_arr[:mid] = arr[:mid]
            stretched_arr[-mid-1:] = arr[-mid-1:]
    
        return stretched_arr
    

    以下是我测试的一些测试用例:

    测试用例:

    In [104]: stretch(arr, stretch_len)   
    Out[104]: array([ 4.,  5.,  1., nan, nan,  2.,  6.,  8.])
    
    In [105]: arr = [4, 5, 1, 2, 6, 8, 9]    
    
    In [106]: stretch(arr, stretch_len)  
    Out[106]: array([ 4.,  5.,  1., nan,  2.,  6.,  8.,  9.])
    
    In [107]: stretch(arr, 9)  
    Out[107]: array([ 4.,  5.,  1., nan, nan,  2.,  6.,  8.,  9.])
    

    【讨论】:

    • 两个连续的 nan 不满足均匀分布的条件。我希望它们之间至少有 2 个样本。
    【解决方案3】:

    虽然Chris 解决了问题,但我找到了一个更简短的答案,这可能会有所帮助,

    def stretch2(x,to,fill=np.nan):
        output  = np.repeat(fill,to)
        foreign = np.linspace(0,to-1,len(x)).round().astype(int)
        output[foreign] = x
        return output
    

    与我的第一次尝试非常相似。时间:

    >>> x = np.random.rand(1000)
    >>> to = 1200
    >>> %timeit stretch(x,to) # Chris' version
    >>> %timeit stretch2(x,to)
    
    996 µs ± 22.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    32.2 µs ± 339 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    

    检查是否正常工作:

    >>> aa = stretch2(x,to)
    >>> np.diff(np.where(np.isnan(aa))[0])
    array([6, 6, 6, ... , 6])
    >>> np.sum(aa[~np.isnan(aa)] - x)
    0.0
    

    检查边界条件:

    >>> aa[:5]
    array([0.78581616, 0.1630689 , 0.52039993,        nan, 0.89844404])
    >>> aa[-5:]
    array([0.7063653 ,        nan, 0.2022172 , 0.94604503, 0.91201897])
    

    都很满意。适用于所有一维数组,也可以推广到与 n-d 数组一起使用,只需进行一些更改。

    【讨论】:

      【解决方案4】:

      您可以使用resize 调整数组大小。

      调整大小后,您可以应用适当的逻辑来重新排列内容。

      查看以下链接: https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.resize.html

      【讨论】:

      • 调整大小会使零结束,那么我如何将它与其他(可能的)零分开?使用调整大小的正确方法是什么?
      猜你喜欢
      • 2016-09-10
      • 2015-11-19
      • 1970-01-01
      • 2015-10-28
      • 1970-01-01
      • 1970-01-01
      • 2011-03-16
      • 2016-01-27
      相关资源
      最近更新 更多