【问题标题】:Replacing 2D subarray in 3D array if condition is met如果满足条件,则替换 3D 数组中的 2D 子数组
【发布时间】:2018-04-29 19:03:58
【问题描述】:

我有一个如下所示的矩阵:

a = np.random.rand(3, 3, 3)

[[[0.04331462, 0.30333583, 0.37462236],
  [0.30225757, 0.35859228, 0.57845153],
  [0.49995805, 0.3539933,  0.11172398]],

 [[0.28983508, 0.31122743, 0.67818926],
  [0.42720309, 0.24416101, 0.5469823 ],
  [0.22894097, 0.76159389, 0.80416832]],

 [[0.25661154, 0.64389696, 0.37555374],
  [0.87871659, 0.27806621, 0.3486518 ],
  [0.26388296, 0.8993144,  0.7857116 ]]]

我想检查每个块是否有小于 0.2 的值。如果值小于 0.2,则整个块等于 0.2。在这种情况下:

[[[0.2 0.2 0.2]
  [0.2 0.2 0.2]
  [0.2 0.2 0.2]]

[[0.28983508 0.31122743 0.67818926]
 [0.42720309 0.24416101 0.5469823 ]
 [0.22894097 0.76159389 0.80416832]]

[[0.25661154 0.64389696 0.37555374]
 [0.87871659 0.27806621 0.3486518 ]
 [0.26388296 0.8993144  0.7857116 ]]]

【问题讨论】:

    标签: python numpy vectorization


    【解决方案1】:

    这是获得所需内容的矢量化方式。
    从您的示例中获取a

    a[(a < 0.2).any(axis=1).any(axis=1)] = 0.2
    print(a)
    

    给予:

    array([[[ 0.2       ,  0.2       ,  0.2       ],
            [ 0.2       ,  0.2       ,  0.2       ],
            [ 0.2       ,  0.2       ,  0.2       ]],
    
           [[ 0.28983508,  0.31122743,  0.67818926],
            [ 0.42720309,  0.24416101,  0.5469823 ],
            [ 0.22894097,  0.76159389,  0.80416832]],
    
           [[ 0.25661154,  0.64389696,  0.37555374],
            [ 0.87871659,  0.27806621,  0.3486518 ],
            [ 0.26388296,  0.8993144 ,  0.7857116 ]]])
    

    说明:

    再举一个例子,每一步都会更清楚:

    a = np.array([[[0.51442898, 0.90447442, 0.45082496],
                   [0.59301203, 0.30025497, 0.43517362],
                   [0.28300437, 0.64143037, 0.73974422]],
                  [[0.228676  , 0.59093859, 0.14441217],
                   [0.37169639, 0.57230533, 0.81976775],
                   [0.95988687, 0.43372407, 0.77616701]],
                  [[0.03098771, 0.80023031, 0.89061113],
                   [0.86998351, 0.39619143, 0.16036088],       
                   [0.24938437, 0.79131954, 0.38140462]]])
    

    让我们看看哪些元素小于0.2:

    print(a < 0.2)
    

    给予:

    array([[[False, False, False],
            [False, False, False],
            [False, False, False]],
    
           [[False, False,  True],
            [False, False, False],
            [False, False, False]],
    
           [[ True, False, False],
            [False, False,  True],
            [False, False, False]]])
    

    从这里我们想获得那些至少有一个True元素的二维数组的索引:[False, True, True]。为此,我们需要np.any。请注意,我将在这里使用np.ndarray.any 方法链接,而不是嵌套np.any 的函数调用。 1

    现在只使用(a &lt; 0.2).any() 将只给出True,因为默认情况下它对所有维度执行逻辑或。我们必须指定axis 参数。在我们的例子中,axis=1axis=2 都可以。2

    print((a < 0.2).any(axis=1))
    

    3

    array([[False, False, False],
           [False, False,  True],
           [ True, False,  True]])
    

    从这里我们通过沿行应用另一个 .any() 来获得所需的布尔索引:

    print((a < 0.2).any(axis=1).any(axis=1))
    

    给予:

    array([False,  True,  True])
    

    实际上,我们可以简单地使用这个boolean index array 来替换原始数组的值:

    a[(a < 0.2).any(axis=1).any(axis=1)] = 0.2
    print(a)
    

    给予:

    array([[[0.51442898, 0.90447442, 0.45082496],
            [0.59301203, 0.30025497, 0.43517362],
            [0.28300437, 0.64143037, 0.73974422]],
    
           [[0.2       , 0.2       , 0.2       ],
            [0.2       , 0.2       , 0.2       ],
            [0.2       , 0.2       , 0.2       ]],
    
           [[0.2       , 0.2       , 0.2       ],
            [0.2       , 0.2       , 0.2       ],
            [0.2       , 0.2       , 0.2       ]]])
    

    1只比较链式:

    a[(a < 0.2).any(axis=1).any(axis=1)] = 0.2
    

    有嵌套:

    a[np.any(np.any(a < 0.2, axis=1), axis=1)] = 0.2
    

    我认为后者更令人困惑。

    2对我来说,起初这很难理解。帮助我的是绘制一个 3x3x3 立方体的图像,打印不同轴的结果,并检查哪个轴对应于哪个方向。此外,这里是在 3D 情况下使用带有 np.sum 的轴的说明:Axis in numpy multidimensional array.

    3人们可能期望立即获得[False, True, True],但事实并非如此。解释见:Small clarification needed on numpy.any for matrices

    【讨论】:

      【解决方案2】:

      既然你的矩阵有三层,试试这个(让你的矩阵是 a):

      for x in a:
          for y in x:
              for z in y:
                  if z < 0.2:
                      z=0.2
      

      【讨论】:

      • 使用 numpy 提高效率的关键是一次对整个数组执行矢量化操作,而不是使用嵌套循环。此外,这不是 OP 所要求的。
      【解决方案3】:
      for i, block in enumerate(a):
          if (block < 0.2).flatten().any():
              a[i] = np.ones(np.shape(block)) * 0.2
      
      print(a)
      
      array([[[ 0.2       ,  0.2       ,  0.2       ],
              [ 0.2       ,  0.2       ,  0.2       ],
              [ 0.2       ,  0.2       ,  0.2       ]],
      
             [[ 0.28983508,  0.31122743,  0.67818926],
              [ 0.42720309,  0.24416101,  0.5469823 ],
              [ 0.22894097,  0.76159389,  0.80416832]],
      
             [[ 0.25661154,  0.64389696,  0.37555374],
              [ 0.87871659,  0.27806621,  0.3486518 ],
              [ 0.26388296,  0.8993144 ,  0.7857116 ]]])
      

      【讨论】:

        猜你喜欢
        • 2012-05-12
        • 2021-12-22
        • 2013-11-15
        • 2018-06-22
        • 1970-01-01
        • 2018-08-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多