簡體   English   中英

反轉具有多個切片對象的 2D NumPy 數組

[英]Reverse a 2D NumPy array with multiple slice objects

問題

我有一個 2D NumPy 數組arr ,對於每一行,我想反轉數組的一部分。 至關重要的是,對於每一行, startstop索引必須是唯一的。 我可以使用以下方法實現這一點。

import numpy as np

arr = np.repeat(np.arange(10)[np.newaxis, :], 3, axis=0)
reverse = np.sort(np.random.choice(arr.shape[1], [arr.shape[0], 2], False))

# arr
# array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
#        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
#        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])

# reverse
# array([[1, 7],
#        [8, 9],
#        [4, 6]])

反轉startstop索引之間的每一行。

for idx, (i, j) in enumerate(reverse):
    arr[idx, i:j+1] = arr[idx, i:j+1][::-1]

# arr 
# array([[0, 7, 6, 5, 4, 3, 2, 1, 8, 9],
#        [0, 1, 2, 3, 4, 5, 6, 7, 9, 8],
#        [0, 1, 2, 3, 6, 5, 4, 7, 8, 9]])

這是否可以使用基本切片和索引? 我嘗試使用reverse的輸出來形成多個slice對象,但是沒有成功。


更新

原始方法與答案的簡單比較。 對於我的數據,該解決方案只需要處理形狀為 (50, 100) 的二維矩陣。

import numpy as np

def reverse_one(arr, n): 
    temp = np.repeat(arr.copy(), n, axis=0)
    reverse = np.sort(np.random.choice(temp.shape[1], [n, 2], False))

    for idx, (i, j) in enumerate(reverse):
        temp[idx, i:j+1] = temp[idx, i:j+1][::-1]

    return temp

def reverse_two(arr, n):
    temp = np.repeat(arr.copy(), n, axis=0)
    reverse = np.sort(np.random.choice(temp.shape[1], [n, 2], False))
    rev = np.ravel_multi_index((np.arange(n)[:, np.newaxis], reverse), temp.shape)
    rev[:, 1] += 1
    idx = np.arange(temp.size).reshape(temp.shape)
    s = np.searchsorted(rev.ravel(), idx, 'right')
    m = (s % 2 == 1)
    g = rev[s[m] // 2]
    idx[m] = g[:, 0] - (idx[m] - g[:, 1]) - 1

    return temp.take(idx)

m = 100
arr = np.arange(m)[np.newaxis, :]

print("reverse_one:")
%timeit reverse_one(arr, m//2)
print("=" * 40)
print("reverse_two:")
%timeit reverse_two(arr, m//2)

在 Jupyter Notebook 中運行以下代碼會得到以下結果。

reverse_one:
1000 loops, best of 5: 202 µs per loop
========================================
reverse_two:
1000 loops, best of 5: 363 µs per loop

這有點棘手,但我想出了一種方法來做到這一點。 但是,高級索引很昂貴,因此您必須根據您擁有的數據查看它是否真的更快。

import numpy as np

np.random.seed(0)
arr = np.repeat(np.arange(10)[np.newaxis, :], 3, axis=0)
reverse = np.sort(np.random.choice(arr.shape[1], [arr.shape[0], 2], False))
print(arr)
# [[0 1 2 3 4 5 6 7 8 9]
#  [0 1 2 3 4 5 6 7 8 9]
#  [0 1 2 3 4 5 6 7 8 9]]
print(reverse)
# [[2 8]
#  [4 9]
#  [1 6]]

# Get "flat" indices of the bounds
rev = np.ravel_multi_index((np.arange(arr.shape[0])[:, np.newaxis], reverse), arr.shape)
# Add one to the second bound (so it is first index after the slice)
rev[:, 1] += 1
# Make array of flat indices for the data
idx = np.arange(arr.size).reshape(arr.shape)
# Find the position of flat indices with respect to bounds
s = np.searchsorted(rev.ravel(), idx, 'right')
# For each "i" within a slice, "s[i]" is odd
m = (s % 2 == 1)
# Replace indices within slices with their reversed ones
g = rev[s[m] // 2]
idx[m] = g[:, 0] - (idx[m] - g[:, 1]) - 1
# Apply indices to array
res = arr.take(idx)
print(res)
# [[0 1 8 7 6 5 4 3 2 9]
#  [0 1 2 3 9 8 7 6 5 4]
#  [0 6 5 4 3 2 1 7 8 9]]

暫無
暫無

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

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