【问题标题】:Select N random rows from a 3D numpy array从 3D numpy 数组中选择 N 个随机行
【发布时间】:2021-12-03 12:55:06
【问题描述】:

我有一个 3D 数组,我想从轴 1 获取随机“集合”(注意:不是 pythonic 集合),N 次。我可以通过嵌套的 For 循环来实现这一点,但我至少需要这样做 10000 次,所以如果可能的话,我需要找到一个矢量化的解决方案。

我将尝试用一个例子来解释这一点。如果我想检索 N 组数据,我想从我的 3D 数组中的轴 1 中为轴 0 中的每个元素选择一个随机索引。例如在我的 N 个集合中的第一个中,我随机选择索引 [0, 2, 1],这与三个不同的数组位置相关:分别为 [0, 0, :][1, 2, :][2, 1, :](即轴 0 每次递增一个,轴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]。这三个随机选择的“光谱”构成了“临时”的第一个条目。这会重复 N 次。
  • 我建议您编辑您的问题以将其清理到最低限度(即,说明您要在axis1中选择随机行但相对于axis0独立),您可以删除所有代码以保留描述和输入/输出示例
  • 感谢大家的帮助,我马上修改。

标签: python arrays numpy vectorization


【解决方案1】:

鉴于您的问题的说明,您希望在轴 1(第二维)上的 3D 数组中选择 N 个随机行,但在轴 0 上独立:

我们称之为数组和 x,y,z 它的 3 个维度。

一个简单的方法是选择 N*x 个随机索引,这样每个 x 就有 N 个。然后在前 2 个维度上展平数组并切片。

示例输入(注意 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) 形状
  • 我也注意到了这一点,但它很容易解决,所以解决方案仍然有效。
【解决方案2】:

澄清问题之前的原始答案,请参阅new answer 进行独立抽样

你可以得到随机索引和切片:

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 有时间我会读你的更新,但你有没有在我的答案底部看到我提供了第二维(轴 1)的解决方案
  • 提前谢谢您。是的,我确实看到了您的第二维(轴 1)示例,但这也不是我所追求的。希望我的编辑可以清除它(再次,抱歉造成混淆!),但要指出为什么您的解决方案对我不起作用:您给出的第二维示例生成一个 (3, N, 7) 数组,其中每个N 数据的三组(轴 0)取自“x”中它们各自的第一个轴 0 等效项。我想要的是一个 (N, 3, 7) 数组,其中沿轴 0 的每组数据是 3 个“样本”,随机取自轴 0 的 4 个“光谱”组中的每一个。
  • @AlexP 我明白了,没问题。为了清楚起见,我提供了another answer
猜你喜欢
  • 2014-05-15
  • 2021-12-14
  • 2017-09-16
  • 1970-01-01
  • 1970-01-01
  • 2019-12-02
  • 2018-06-07
  • 1970-01-01
相关资源
最近更新 更多