如何优雅地“重构”一个numpy数组

时间:2017-09-26 01:15:25

标签: python arrays numpy scipy

我正在使用numpy.array作为数据缓冲区,我正在寻找一种优雅的reframe方式,以便保留一部分初始数据,具体取决于新的成帧条件(缓冲区可能包含shrunkexpandedshiftedshift + 2前者的组合

Reframe可能不是这里的正确用语。但是下面的例子有希望说清楚:

为简单起见,我将使用False来说明一个空的reframed数组元素:

import numpy as np

# Init buffer
data = 10 * np.arange(6) + 10 # dummy data for this example
# Result: array([10, 20, 30, 40, 50, 60]) # 

缩小缓冲区:

# shift start by 1 to the right, and end by 1 to the left
reframe(data,1,-1) # basically doing: buffer[1:-1]
# Desired Result = array([20, 30, 40, 50]) #

展开缓冲区:

# shift start by 2 to the left, and end by 1 to the 
reframe(data,-2,1)
# Desired Result: array([False, False, 10, 20, 30, 40, 50, 60, False]) # 

向左或向右移动缓冲区+展开:

# shift start by 2 to the right, and end by 4 to the right 
reframe(data,2,4)
# Desired Result: array([30, 40, 50, 60, False, False, False, False]) # 

再次在这个例子中,我使用False,我期望一个新的空reframed数组元素。这可以是np.empty,或np.NaN等等......

为了实现我的目标,我写了以下内容:

import numpy as np

def reframe(data,start,end):

    # Shrinking: new array is a substet of original
    if start >= 0 and end <=0:
        if start > 0 and end < 0:
            return data[start:end]
        if start > 0:
            return data[start:]
        return data[:end]

    # Expand, new array fully contains original
    elif start <= 0 and end >= 0:
        new = np.zeros(data.shape[0] + end - start).astype(data.dtype)
        new[abs(start):data.shape[0]+2] = data
        return new

    # Shift, new array may have a portion of old
    else:
        new = np.zeros((data.shape[0]-start+end)).astype(data.dtype)

        # Shift Right
        if start > 0:
            new[:data.shape[0]-start] = data[start:]
            return new

        # Shift Left
        if end < 0:
            new[:data.shape[0]+end] = data[::-1][abs(end):]
            return new[::-1]

测试:

print reframe(data,1,-1) # [20 30 40 50]
print reframe(data,-2,1) # [ 0  0 10 20 30 40 50 60  0]
print reframe(data,2,4)  # [30 40 50 60  0  0  0  0]

所以这适用于我的目的,但我希望会有一些更优雅的东西。

同样在我的现实应用程序中,我的阵列数十万,所以效率是必须的。

1 个答案:

答案 0 :(得分:2)

import numpy as np

def reframe(x, start, end, default=0):
    shape = list(x.shape)
    orig_length = shape[0]
    shape[0] = length = end - start

    old_start = max(0, start)
    old_end = min(end, length + 1, orig_length)
    new_start = -start if start < 0 else 0
    new_end = new_start + old_end - old_start

    x_new = np.empty(shape, dtype=x.dtype)
    x_new[:] = default
    x_new[new_start:new_end] = x[old_start:old_end]
    return x_new

x = np.arange(6) + 1

x_new = reframe(x, 1, 4)
print('1. ', x_new)

x_new = reframe(x, -4, 4)
print('2. ', x_new)

x_new = reframe(x, 1, 7)
print('3. ', x_new)

x_new = reframe(x, -1, 9, default=4)
print('4. ', x_new)

x = np.arange(100).reshape(20, 5) + 1
x_new = reframe(x, -1, 2)
print('5. ', x_new)

输出:

1. [2 3 4]
2. [0 0 0 0 1 2 3 4]
3. [2 3 4 5 6 0]
4. [4 1 2 3 4 5 6 4 4 4]
5. [[ 0  0  0  0  0]
    [ 1  2  3  4  5]
    [ 6  7  8  9 10]]

我相信这符合要求。在问题中我不清楚的主要部分是为什么开始是10而结尾是15,而不是说0和5.这个函数是0索引的。启动的负索引意味着您想从头开始扩展到左侧。此外,它不具有包容性,因为这通常是python / numpy如何工作。

很难知道默认值应该是什么,因为我不知道数组的类型。因此,我添加了一个默认参数,它将初始化数组。