【问题标题】:How to elegantly "reframe" a numpy array如何优雅地“重构”一个 numpy 数组
【发布时间】:2017-09-26 01:15:25
【问题描述】:

我正在使用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]

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

在我的实际应用程序中,我的数组也有数十万个,所以效率是必须的。

【问题讨论】:

  • 仅适用于一维阵列还是您还想“重构”ND 阵列?
  • @MSeifert 在我当前的用例中,我需要“重构”一维数组和二维数组,但在二维数组的情况下,我只关心它是否沿第一个轴。因此,如果您有一个仅适用于一维数组的解决方案,我不介意沿第一个轴元素明智地应用二维数组

标签: python arrays numpy scipy


【解决方案1】:
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 的工作方式。

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

【讨论】:

  • 你是对的,开始/结束时间使问题变得混乱。我编辑了我的问题以完全删除它们,而只是将这些值视为数组开始和结束的偏移量。
  • 我看到你用解决方案更新了这个问题。你能解释一下为什么我写的 reframe 不能完全满足你的需要吗?
  • 我添加的解决方案是为了说明我需要的行为。您的解决方案比我的一堆 if 语句更优雅。 :)
猜你喜欢
  • 1970-01-01
  • 2017-06-13
  • 1970-01-01
  • 2019-06-27
  • 2017-01-20
  • 1970-01-01
  • 2015-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多