代码之家  ›  专栏  ›  技术社区  ›  mccandar

拉伸阵列并填充NaN

  •  2
  • mccandar  · 技术社区  · 7 年前

    我有一个长度为n的一维numpy数组,我想将其拉伸到m(n<m)并系统地添加numpy.n a 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),是否有任何线索可以克服这一点?

    4 回复  |  直到 7 年前
        1
  •  2
  •   Chris    7 年前

    使用 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 ,它将输入数组拆分为尽可能相同的长度

    循环赛 因为 NPARRAY分裂 比间隙多生成一个数组,循环(即交替迭代)授予 np.nan 从不在结果的两端。

        2
  •  1
  •   kmario23 Mazdak    7 年前

    这种方法将非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.])
    
        3
  •  1
  •   mccandar    7 年前

    虽然 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
  •  0
  •   Jay    7 年前

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

    一旦调整了大小,就可以应用适当的逻辑来重新排列内容。

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