簡體   English   中英

"一次從一個numpy數組中選擇多個切片"

[英]Selecting multiple slices from a numpy array at once

我正在尋找一種方法來一次從一個 numpy 數組中選擇多個切片。 假設我們有一個一維數據數組,並且想要提取它的三個部分,如下所示:

data_extractions = []

for start_index in range(0, 3):
    data_extractions.append(data[start_index: start_index + 5])

stride_tricks可以做到這一點

a = np.arange(10)
b = np.lib.stride_tricks.as_strided(a, (3, 5), 2 * a.strides)
b
# array([[0, 1, 2, 3, 4],
#        [1, 2, 3, 4, 5],
#        [2, 3, 4, 5, 6]])

請注意, b引用相同的存儲器如a ,實際上多次(例如b[0, 1]b[1, 0]是相同的存儲器地址)。 因此,在使用新結構之前制作副本是最安全的。

nd 可以以類似的方式完成,例如 2d -> 4d

a = np.arange(16).reshape(4, 4)
b = np.lib.stride_tricks.as_strided(a, (3,3,2,2), 2*a.strides)
b.reshape(9,2,2) # this forces a copy
# array([[[ 0,  1],
#         [ 4,  5]],

#        [[ 1,  2],
#         [ 5,  6]],

#        [[ 2,  3],
#         [ 6,  7]],

#        [[ 4,  5],
#         [ 8,  9]],

#        [[ 5,  6],
#         [ 9, 10]],

#        [[ 6,  7],
#         [10, 11]],

#        [[ 8,  9],
#         [12, 13]],

#        [[ 9, 10],
#         [13, 14]],

#        [[10, 11],
#         [14, 15]]])

您可以使用索引將您想要的行選擇為適當的形狀。 例如:

 data = np.random.normal(size=(100,2,2,2))

 # Creating an array of row-indexes
 indexes = np.array([np.arange(0,5), np.arange(1,6), np.arange(2,7)])
 # data[indexes] will return an element of shape (3,5,2,2,2). Converting
 # to list happens along axis 0
 data_extractions = list(data[indexes])

 np.all(data_extractions[1] == data[1:6])
 True

最后的比較是針對原始數據。

在這篇文章中,是一種使用np.lib.stride_tricks.as_strided strided-indexing scheme方法,它基本上在輸入數組中創建一個視圖,因此創建非常有效,並且視圖不占用更多內存空間。 此外,這適用於具有通用維數的 ndarrays。

這是實現 -

def strided_axis0(a, L):
    # Store the shape and strides info
    shp = a.shape
    s  = a.strides

    # Compute length of output array along the first axis
    nd0 = shp[0]-L+1

    # Setup shape and strides for use with np.lib.stride_tricks.as_strided
    # and get (n+1) dim output array
    shp_in = (nd0,L)+shp[1:]
    strd_in = (s[0],) + s
    return np.lib.stride_tricks.as_strided(a, shape=shp_in, strides=strd_in)

4D陣列案例的示例運行 -

In [44]: a = np.random.randint(11,99,(10,4,2,3)) # Array

In [45]: L = 5      # Window length along the first axis

In [46]: out = strided_axis0(a, L)

In [47]: np.allclose(a[0:L], out[0])  # Verify outputs
Out[47]: True

In [48]: np.allclose(a[1:L+1], out[1])
Out[48]: True

In [49]: np.allclose(a[2:L+2], out[2])
Out[49]: True

您可以使用准備好的切片數組對數組進行切片

a = np.array(list('abcdefg'))

b = np.array([
        [0, 1, 2, 3, 4],
        [1, 2, 3, 4, 5],
        [2, 3, 4, 5, 6]
    ])

a[b]

但是, b不必以這種方式手動生成。 它可以更加動態

b = np.arange(5) + np.arange(3)[:, None]

在一般情況下,您必須在構建索引或收集結果時進行某種迭代 - 和串聯。 只有當切片模式本身是規則的時,您才能通過as_strided使用廣義切片。

接受的答案構造了一個索引數組,每個切片一行。 所以這是對切片進行迭代,而arange本身是一個(快速)迭代。 並且np.array將它們連接到一個新軸上( np.stack概括了這一點)。

In [264]: np.array([np.arange(0,5), np.arange(1,6), np.arange(2,7)])
Out[264]: 
array([[0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6]])

indexing_tricks方便的方法來做同樣的事情:

In [265]: np.r_[0:5, 1:6, 2:7]
Out[265]: array([0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6])

這需要切片符號,用arange擴展它並連接。 它甚至可以讓我擴展並連接成 2d

In [269]: np.r_['0,2',0:5, 1:6, 2:7]
Out[269]: 
array([[0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6]])

In [270]: data=np.array(list('abcdefghijk'))
In [272]: data[np.r_['0,2',0:5, 1:6, 2:7]]
Out[272]: 
array([['a', 'b', 'c', 'd', 'e'],
       ['b', 'c', 'd', 'e', 'f'],
       ['c', 'd', 'e', 'f', 'g']], 
      dtype='<U1')
In [273]: data[np.r_[0:5, 1:6, 2:7]]
Out[273]: 
array(['a', 'b', 'c', 'd', 'e', 'b', 'c', 'd', 'e', 'f', 'c', 'd', 'e',
       'f', 'g'], 
      dtype='<U1')

索引后連接結果也有效。

In [274]: np.stack([data[0:5],data[1:6],data[2:7]])

我對其他 SO 問題的記憶是相對時間處於相同的數量級。 例如,它可能隨着切片的數量與它們的長度而變化。 總的來說,必須從源復制到目標的值的數量是相同的。

如果切片的長度不同,則必須使用平面索引。

無論您選擇哪種方法,如果 2 個切片包含相同的元素,則它不能正確支持數學運算,除非您使用ufunc.at<\/code> ,它可能比循環效率低。 供測試用:

def as_strides(arr, window_size, stride, writeable=False):
    '''Get a strided sub-matrices view of a 4D ndarray.

    Args:
        arr (ndarray): input array with shape (batch_size, m1, n1, c).
        window_size (tuple): with shape (m2, n2).
        stride (tuple): stride of windows in (y_stride, x_stride).
        writeable (bool): it is recommended to keep it False unless needed
    Returns:
        subs (view): strided window view, with shape (batch_size, y_nwindows, x_nwindows, m2, n2, c)

    See also numpy.lib.stride_tricks.sliding_window_view
    '''
    batch_size = arr.shape[0]
    m1, n1, c = arr.shape[1:]
    m2, n2 = window_size
    y_stride, x_stride = stride

    view_shape = (batch_size, 1 + (m1 - m2) // y_stride,
                  1 + (n1 - n2) // x_stride, m2, n2, c)
    strides = (arr.strides[0], y_stride * arr.strides[1],
               x_stride * arr.strides[2]) + arr.strides[1:]
    subs = np.lib.stride_tricks.as_strided(arr,
                                           view_shape,
                                           strides=strides,
                                           writeable=writeable)
    return subs


import numpy as np
np.random.seed(1)

Xs = as_strides(np.random.randn(1, 5, 5, 2), (3, 3), (2, 2), writeable=True)[0]
print('input\n0,0\n', Xs[0, 0])
np.add.at(Xs, np.s_[:], 5)
print('unbuffered sum output\n0,0\n', Xs[0,0])
np.add.at(Xs, np.s_[:], -5)
Xs = Xs + 5
print('normal sum output\n0,0\n', Xs[0, 0])

我們可以為此使用列表理解

data=np.array([1,2,3,4,5,6,7,8,9,10])
data_extractions=[data[b:b+5] for b in [1,2,3,4,5]]
data_extractions

結果

[array([2, 3, 4, 5, 6]), array([3, 4, 5, 6, 7]), array([4, 5, 6, 7, 8]), array([5, 6, 7, 8, 9]), array([ 6,  7,  8,  9, 10])]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM