numpy 随机播放一小部分子数组

numpy shuffle a fraction of sub-arrays

我在 ndim = 3 的数组中有未定义形状的单热编码数据,例如:

import numpy as np

arr = np.array([ # Axis 0
    [ # Axis 1
        [0, 1, 0], # Axis 2
        [1, 0, 0],
    ],
    [
        [0, 0, 1],
        [0, 1, 0],
    ],
])

我想要的是沿 axis=2.

打乱已知部分子数组的值

如果这个分数是0.25,那么结果可能是:

arr = np.array([
    [
        [1, 0, 0], # Shuffling happened here
        [1, 0, 0],
    ],
    [
        [0, 0, 1],
        [0, 1, 0],
    ],
])

我知道如何使用迭代方法来做到这一点,例如:

for i in range(arr.shape[0]):
    for j in range(arr.shape[1]):
        if np.random.choice([0, 1, 2, 3]) == 0:
            np.random.shuffle(arr[i][j])

但这是非常低效的。

编辑:正如评论中所建议的,已知分数的随机选择应遵循统一的规律。

您的迭代方法很棒,就所涉及的逻辑操作数而言绝对是最佳解决方案。据我所知,做得更好的唯一方法是利用 numpy 的矢量化加速。以下代码为示例

def permute_last_maybe(x):
    N, M, K = x.shape
    y = np.transpose(x, [2, 0, 1])
    y = np.random.permutation(y)
    y = np.transpose(y, [1, 2, 0])
    mask = (np.random.random((N, M, 1)) > 0.25) * np.ones([N, M, K])
    return np.where(mask, x, y)

timeit 魔术显示 300 us 而不是 4.2 ms,数组大小为 (40, 40, 30)。 请注意,此代码不使用 numpy 中的新 random Generators(我尝试过,但创建 class 实例的重载很重要)。

我可能还应该提到这个函数不会改变给定的数组 x 而是 returns 它的一个副本。

一种方法:

import numpy as np

np.random.seed(42)

fraction = 0.25
total = arr.shape[0] * arr.shape[1]

# pick arrays to be shuffled
indices = np.random.choice(np.arange(total), size=int(total * fraction), replace=False)

# convert the each index to the corresponding multi-index
multi_indices = np.unravel_index(indices, arr.shape[:2])

# create view using multi_indices
selected = arr[multi_indices]

# shuffle select by applying argsort on random values of the same shape
shuffled = np.take_along_axis(selected, np.argsort(np.random.random(selected.shape), axis=1), axis=1)

# set the array to the new values
arr[multi_indices] = shuffled
print(arr)

输出(单个运行)

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

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