2017-09-26 31 views
0

我正在使用一個numpy.array作爲數據緩衝區,我正在尋找一個優雅的方式來reframe它,以便它保留一部分初始數據,這取決於新的幀條件(緩衝液可以具有shrunkexpandedshiftedshift + 2前的組合)如何優雅地「重構」一個numpy陣列

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] 

所以此工程在我的目的,但我希望能有些更優雅的東西。

另外在我的現實生活中,我的數組有數十萬個,所以效率是必須的。

+0

只適用於1D陣列,或者你也想「重構」ND陣列? – MSeifert

+0

@MSeifert在我當前的用例中,我需要「重新構建」1d和2d數組,但在2d數組的情況下,我只關心它是否沿着第1軸。所以,如果你有一個只適用於1d數組的解決方案,我不介意沿着第1軸元素應用它的2D陣列 – Fnord

回答

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的工作方式。

很難知道默認值應該是什麼,因爲我不知道數組的類型。因此,我添加了一個默認參數,它將初始化數組。

+0

你是對的,開始/結束時間混淆了這個問題。我編輯我的問題完全刪除它們,而只是將值視爲數組開始和結束的偏移量。 – Fnord

+0

我看到你用解決方案更新了這個問題。你能解釋一下爲什麼我寫的重構不能滿足你的需求嗎? – BradMcDanel

+0

我添加的解決方案是爲了說明我需要的行爲。你的解決方案比我的一堆if語句更優雅。 :) – Fnord