从一个3D numpy数组中选择N个随机行

3
我有一个3D数组,我想从轴1中随机选取N个“集合”(注意:不是Pythonic的set)。如果可以的话,我希望找到矢量化解决方案。我可以通过嵌套for循环实现这一点,但我需要至少执行10000次。
我将尝试使用示例来解释这个问题。如果我想检索N组数据,我想为轴0中的每个元素选择一个在我的3D数组中的轴1中的随机索引。例如,在我的N组中的第一组中,我随机选择索引[0, 2, 1],这对应于三个不同的数组位置:[0, 0,:],[1, 2,:]和[2, 1,:],分别(即轴0每次增加1,轴1基于随机选择的索引)。
以下是伪代码中的数值示例:
# Create some arbitrary data (EDIT: based on mozway's answer)
a = array([[[ 0. ,  4. ,  8. , 12. , 16. , 20. , 24. ],
            [ 1. ,  5. ,  9. , 13. , 17. , 21. , 25. ],
            [ 2. ,  6. , 10. , 14. , 18. , 22. , 26. ],
            [ 3. ,  7. , 11. , 15. , 19. , 23. , 27. ]],

           [[ 0.1,  4.1,  8.1, 12.1, 16.1, 20.1, 24.1],
            [ 1.1,  5.1,  9.1, 13.1, 17.1, 21.1, 25.1],
            [ 2.1,  6.1, 10.1, 14.1, 18.1, 22.1, 26.1],
            [ 3.1,  7.1, 11.1, 15.1, 19.1, 23.1, 27.1]],

           [[ 0.2,  4.2,  8.2, 12.2, 16.2, 20.2, 24.2],
            [ 1.2,  5.2,  9.2, 13.2, 17.2, 21.2, 25.2],
            [ 2.2,  6.2, 10.2, 14.2, 18.2, 22.2, 26.2],
            [ 3.2,  7.2, 11.2, 15.2, 19.2, 23.2, 27.2]]])


# Define the number of requested sets
N = 2

# Define the chosen data per 'set' (normally would be random)
idx = [[0, 2, 1], [1, 3, 3]]

# First set would give (with choices [0, 2, 1]):
arr = [[ 0. ,  4. , 8.  , 12. , 16. , 20. , 24. ],
       [ 2.1,  6.1, 10.1, 14.1, 18.1, 22.1, 26.1],
       [ 1.2,  5.2, 9.2 , 13.2, 17.2, 21.2, 25.2]]

# Second set would give (with choices [1, 3, 3]):
arr = [[ 1. ,  5. ,  9. , 13. , 17. , 21. , 25. ],
       [ 3.1,  7.1, 11.1, 15.1, 19.1, 23.1, 27.1],
       [ 3.2,  7.2, 11.2, 15.2, 19.2, 23.2, 27.2]]

# So, the final output would combine all sets:
arr = [[[ 0. ,  4. , 8.  , 12. , 16. , 20. , 24. ],
        [ 2.1,  6.1, 10.1, 14.1, 18.1, 22.1, 26.1],
        [ 1.2,  5.2, 9.2 , 13.2, 17.2, 21.2, 25.2]],

        [ 1. ,  5. ,  9. , 13. , 17. , 21. , 25. ],
        [ 3.1,  7.1, 11.1, 15.1, 19.1, 23.1, 27.1],
        [ 3.2,  7.2, 11.2, 15.2, 19.2, 23.2, 27.2]]]

你能在不涉及循环的情况下解释一下你的目标吗?例如,从 x 开始,你如何选择要产生最终输出的元素? - mozway
基于我的示例,当第一次通过循环时,目标是收集3个数据片段,每个片段来自4个不同的“光谱”集合,即从第一个“行”中随机选择一个片段:[1, 2, ..., 7],[2, 3, ..., 8],[3, 4, ..., 9],[4, 5, ..., 10],接下来从第二行选择下一个片段:[1, 2, ..., 33],[2, 3, ..., 34],[3, 4, ..., 35],[4, 5, ..., 36],最后一个片段来自第三行:[1, 2, ..., 37],[2, 3, ..., 38],[3, 4, ..., 39],[4, 5, ..., 40]。这三个随机选择的“光谱”形成了“temps”的第一个条目。这将重复N次。 - AlexP
我建议您编辑您的问题,使其最简化(即,解释您想要独立于axis0选择axis1中的随机行),您可以删除所有代码,只留下描述和输入/输出示例。 - mozway
1
谢谢你的所有帮助,我一会儿就编辑。 - AlexP
2个回答

2
鉴于您的问题澄清,您想在第二维度上(轴1)选择3D数组中的N个随机行,但与轴0独立:
我们将其称为数组a,其三个维度为x、y和z。
一种简单的方法是选择N * x个随机索引,以便每个x有N个。然后将数组展平到前两个维度并切片。
示例输入(请注意x / x.1 / x.2以跟踪原始维度):
array([[[ 0. ,  4. ,  8. , 12. , 16. , 20. , 24. ],
        [ 1. ,  5. ,  9. , 13. , 17. , 21. , 25. ],
        [ 2. ,  6. , 10. , 14. , 18. , 22. , 26. ],
        [ 3. ,  7. , 11. , 15. , 19. , 23. , 27. ]],

       [[ 0.1,  4.1,  8.1, 12.1, 16.1, 20.1, 24.1],
        [ 1.1,  5.1,  9.1, 13.1, 17.1, 21.1, 25.1],
        [ 2.1,  6.1, 10.1, 14.1, 18.1, 22.1, 26.1],
        [ 3.1,  7.1, 11.1, 15.1, 19.1, 23.1, 27.1]],

       [[ 0.2,  4.2,  8.2, 12.2, 16.2, 20.2, 24.2],
        [ 1.2,  5.2,  9.2, 13.2, 17.2, 21.2, 25.2],
        [ 2.2,  6.2, 10.2, 14.2, 18.2, 22.2, 26.2],
        [ 3.2,  7.2, 11.2, 15.2, 19.2, 23.2, 27.2]]])

处理中:
N = 2
# sample with repeats
idx = np.random.randint(y, size=N*x)
corr = np.repeat(np.arange(0,(x-1)*y+1, y), N)
idx += corr
# sample without repeats
idx = np.concatenate([np.random.choice(list(range(y)), replace=False, size=N)+(i*y) for i in range(x)])
# slice array
a.reshape(x*y,z)[idx].reshape(x,N,z).swapaxes(0,1)

可能的输出(N,x,z)形状:
array([[[ 0. ,  4. ,  8. , 12. , 16. , 20. , 24. ],
        [ 1.1,  5.1,  9.1, 13.1, 17.1, 21.1, 25.1],
        [ 0.2,  4.2,  8.2, 12.2, 16.2, 20.2, 24.2]],

       [[ 3. ,  7. , 11. , 15. , 19. , 23. , 27. ],
        [ 3.1,  7.1, 11.1, 15.1, 19.1, 23.1, 27.1],
        [ 1.2,  5.2,  9.2, 13.2, 17.2, 21.2, 25.2]]])

我意识到忘记在末尾添加.reshape(x,N,z).swapaxes(0,1)以获得(N,x,z)形状。 - mozway

1

在问题澄清之前的原始答案,请参见新答案以进行独立抽样

您可以获取随机索引并进行切片:

N = 2

# get random indices on the first dimension
idx = np.random.choice(np.arange(x.shape[0]), size=N)

# slice
x[idx]

示例输出(形状:(2,3,7)):

array([[[ 1,  2,  5, 10, 17, 26, 37],
        [ 2,  3,  6, 11, 18, 27, 38],
        [ 3,  4,  7, 12, 19, 28, 39],
        [ 4,  5,  8, 13, 20, 29, 40]],

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

其他维度的示例:

# second dimension (axis 1)
idx = np.random.choice(np.arange(x.shape[1]), size=N)
x[:, idx]

谢谢您的回答。正如我在对@warped的评论中提到的那样,我已经进行了编辑,试图进一步解释我的问题! - AlexP
@AlexP 我会在有时间的时候阅读你的更新,但是你有没有看到我在答案底部提供了第二维度(轴1)的解决方案。 - mozway
谢谢您的提前帮助。是的,我看到了您的二维(轴1)示例,但它也不是我想要的。希望我的编辑能够澄清(再次抱歉造成困扰!),但是要指出为什么您的解决方案对我无效:您给出的第二个示例生成一个(3,N,7)数组,其中每个三个集合(轴0)的N个数据都取自它们各自在“x”中的第一个轴0等价物。我想要的是一个(N,3,7)数组,其中沿轴0的每组数据都是3个“样本”,分别从轴0的4个“光谱”集合中随机选择一个。 - AlexP
@AlexP 我看到了,没问题。我提供了另一个答案以便更清楚。 - mozway

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接