Numpy 2D数组在行而不是列之间移动元素

whhtz7ly  于 2022-12-23  发布在  其他
关注(0)|答案(5)|浏览(160)

我有下面的二维数组:

seq_length = 5
x = np.array([[0, 2, 0, 4], [5,6,7,8]])
x_repeated = np.repeat(x, seq_length, axis=1)

[[0 0 0 0 0 2 2 2 2 2 0 0 0 0 0 4 4 4 4 4]
 [5 5 5 5 5 6 6 6 6 6 7 7 7 7 7 8 8 8 8 8]]

我想根据seq_lengthx_repeated进行混洗,这样seq的所有项都将混洗在一起。
例如,可能的随机播放:

[[0 0 0 0 0 6 6 6 6 6 0 0 0 0 0 8 8 8 8 8]
 [5 5 5 5 5 2 2 2 2 2 7 7 7 7 7 4 4 4 4 4]]

谢啦,谢啦

idv4meu8

idv4meu81#

你可以这样做:

import numpy as np

seq_length = 5
x = np.array([[0, 2, 0, 4], [5, 6, 7, 8]])

swaps = np.random.choice([False, True], size=4)

for swap_index, swap in enumerate(swaps):
    if swap:
        x[[0, 1], swap_index] = x[[1, 0], swap_index]

x_repeated = np.repeat(x, seq_length, axis=1)

您还可以利用True为非零值这一事实,将for替换为:

for swap_index in swaps.nonzero()[0]:
    x[[0, 1], swap_index] = x[[1, 0], swap_index]

关键是我在np.repeat调用之前进行了shuffling/swapping,这比在调用之后进行要高效得多(同时满足了需要交换的值序列的要求),每对相同值的序列有50%的机会进行交换。

6yoyoihd

6yoyoihd2#

设法解决它如下方式:

items_count = x.shape[-1]    
swap_flags = np.repeat(np.random.choice([0, 1], size=items_count), single_item_length)

给出:

[1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1]

for idx, flag in enumerate(swap_flags):
    if flag:
        x_repeated[0,idx], x_repeated[1,idx] = x_repeated[1,idx], x_repeated[0,idx]

结果:

[[5 5 5 5 5 6 6 6 6 6 0 0 0 0 0 8 8 8 8 8]
 [0 0 0 0 0 2 2 2 2 2 7 7 7 7 7 4 4 4 4 4]]

仍然不是那么优雅的numpy方式。

gijlo24d

gijlo24d3#

下面是我的尝试:

def randomize_blocks(arr):
  """ Shuffles an n-dimensional array given consecutive blocks of numbers.
  """
  groups = (np.diff(arr.ravel(), prepend=0) != 0).cumsum().reshape(arr.shape)
  u, c = np.unique(groups, return_counts=True)
  np.random.shuffle(u)
  o = np.argsort(u)
  return arr.ravel()[np.argsort(np.repeat(u, c[o]))].reshape(arr.shape)

∮ ∮ ∮ ∮ ∮一个月一个月
首先我们要分组

groups = (np.diff(arr.ravel(), prepend=0) != 0).cumsum().reshape(arr.shape)
array([[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3],
       [4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7]])

然后,我们得到每个组的 * unique * 和 * count *。

u, c = np.unique(groups, return_counts=True)
>>> print(u, c)
(array([6, 0, 3, 5, 2, 4, 7, 1]),
 array([5, 5, 5, 5, 5, 5, 5, 5]))

最后,我们对唯一组进行shuffle,重构数组,并使用argsort对混洗后的唯一组进行重新排序。

o = np.argsort(u)
arr.ravel()[np.argsort(np.repeat(u, c[o]))].reshape(arr.shape)

示例用法:

>>> randomize_blocks(arr)
array([[0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5],
       [7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6]])
>>> randomize_blocks(arr)
array([[6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 2, 2, 2, 2, 2]])
rm5edbpk

rm5edbpk4#

import numpy as np

m = np.array([[0, 2, 0, 4], [5, 6, 7, 8]])

m_rows = len(m) ### Save rows number
m_cols = len(m[0]) ### Save cols number
n_duplicate = 5 ### Define your replication number here

# Flatten the numpy matrix
m = m.flatten()
# Randomize the flattened matrix m
np.random.shuffle(m)
# Duplicate elements
m = np.repeat(m, n_duplicate, axis=0)
# Reshape numpy array
m = np.reshape(m, (m_rows, n_duplicate*m_cols))

### array([[6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2],
###        [7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0]])
cbwuti44

cbwuti445#

下面是一个完全到位的解决方案,不需要分配和生成随机索引:

import numpy as np

def row_block_shuffle(a: np.ndarray, seq_len: int):
    cols = a.shape[1]
    rng = np.random.default_rng()
    for block in x_repeated.T.reshape(cols // seq_len, seq_length, -1).transpose(0, 2, 1):
        rng.shuffle(block)

if __name__ == "__main__":
    seq_length = 5
    x = np.array([[0, 2, 0, 4], [5, 6, 7, 8]])
    x_repeated = np.repeat(x, seq_length, axis=1)

    row_block_shuffle(x_repeated, seq_length)
    print(x_repeated)

输出:

[[5 5 5 5 5 6 6 6 6 6 7 7 7 7 7 8 8 8 8 8]
 [0 0 0 0 0 2 2 2 2 2 0 0 0 0 0 4 4 4 4 4]]

我所做的是创建与原始数组共享内存的"块":

>>> x_repeated.T.reshape(cols // seq_len, seq_length, -1).transpose(0, 2, 1)
[[[0 0 0 0 0]
  [5 5 5 5 5]]

 [[2 2 2 2 2]
  [6 6 6 6 6]]

 [[0 0 0 0 0]
  [7 7 7 7 7]]

 [[4 4 4 4 4]
  [8 8 8 8 8]]]

然后我对每个"块"进行洗牌,这将反过来对原始数组进行洗牌。我相信这是对大型数组最有效的解决方案,因为这个解决方案是尽可能到位的。这个答案至少支持了我的假设:
https://stackoverflow.com/a/5044364/13091658
还有!你所面临的一般问题是排序数组的"滑动窗口视图",所以如果你想排序数组中水平和垂直移动的"窗口",你可以在这里看到我以前对滑动窗口相关问题的回答:
https://stackoverflow.com/a/67416335/13091658
https://stackoverflow.com/a/69924828/13091658

相关问题