【问题标题】:Numpy broadcasting to the 4th dimension: ... vs. : vs NoneNumpy 广播到第 4 维:... vs. : vs None
【发布时间】:2016-11-02 23:37:02
【问题描述】:

在 montecarlo 模拟中,我有以下 7 张扑克牌,供 2 名玩家和 3 次不同的 montecarlo 运行。

self.cards:

array([[[  6.,  12.],
    [  1.,   6.],
    [  3.,   3.],
    [  8.,   8.],
    [  1.,   1.],
    [  4.,   4.],
    [  2.,   2.]],

   [[  6.,   7.],
    [  1.,   1.],
    [  3.,   3.],
    [  2.,   2.],
    [ 12.,  12.],
    [  5.,   5.],
    [ 10.,  10.]],

   [[  6.,   3.],
    [  1.,  11.],
    [  2.,   2.],
    [  6.,   6.],
    [ 12.,  12.],
    [  6.,   6.],
    [  7.,   7.]]])

对应的花色是:

self.suits

array([[[ 2.,  1.],
    [ 1.,  2.],
    [ 2.,  2.],
    [ 2.,  2.],
    [ 1.,  1.],
    [ 2.,  2.],
    [ 2.,  2.]],

   [[ 2.,  0.],
    [ 1.,  3.],
    [ 2.,  2.],
    [ 0.,  0.],
    [ 1.,  1.],
    [ 1.,  1.],
    [ 1.,  1.]],

   [[ 2.,  2.],
    [ 1.,  0.],
    [ 3.,  3.],
    [ 2.,  2.],
    [ 1.,  1.],
    [ 1.,  1.],
    [ 1.,  1.]]])

现在我想“合并”数组,使卡片数组扩展到第 4 维,大小为 4:0 包含所有套装==1、1 所有套装==2、2 所有套装==3 和 3 都适合 ==4

我可以轻松创建 4 个不同的数组:

club_cards=(self.suits == 1) * self.cards 
diamond_cards=(self.suits == 2) * self.cards 
heart_cards=(self.suits == 3) * self.cards 
spade_cards=(self.suits == 4) * self.cards

然后将它们堆叠在一起:

stacked_array=np.stack((club_cards,diamond_cards, heart_cards, spade_cards),axis=0)

预期结果的形状为 (4, 3, 8, 2)

array([[[[  1.,  12.],
         [  1.,   1.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [-11.,   0.]],

        [[ 12.,  12.],
         [ 10.,  10.],
         [  5.,   5.],
         [  1.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.]],

        [[ 12.,  12.],
         [  7.,   7.],
         [  6.,   6.],
         [  1.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.]]],


       [[[  8.,   8.],
         [  6.,   6.],
         [  4.,   4.],
         [  3.,   3.],
         [  2.,   2.],
         [  0.,   0.],
         [  0.,   0.],
         [ -4.,  -4.]],

        [[  6.,   3.],
         [  3.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [ -6.,  -9.]],

        [[  6.,   6.],
         [  6.,   3.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [ -6.,  -6.]]],


       [[[  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [-12., -12.]],

        [[  0.,   1.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [-12., -11.]],

        [[  2.,   2.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [-10., -10.]]],


       [[[  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [-12., -12.]],

        [[  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [-12., -12.]],

        [[  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [  0.,   0.],
         [-12., -12.]]]])

虽然这在上述情况下可能有意义,但并非总是可行,特别是如果需要堆叠在一起的情况超过 4 个,这让我想到了我的问题:

如何通过广播做到这一点?下面是我的具体问题:

我已经尝试了一些东西。

  1. 让我们专注于第一步,让布尔值在做花色==np.arange(4) (第二步只是与需要以与广播相同的方式广播的卡片的乘法西装)。我的理解是我们想为 suits 数组添加一个维度,所以我们不应该用 3 点符号表示这个:self.suits[...,:,:,:]==np.arange(4)?相反,以下似乎几乎可以工作:self.suits[:,:,:,None]==np.arange(4)(除了它在错误的位置添加了维度)。以下内容也不起作用:self.suits[None,:,:,:]==np.arange(4)。如何在第一维中扩展数组,使结果与上述堆栈中的结果相同?

  2. 什么情况下需要...,什么时候需要None?我希望使用...,因为这表明这个维度需要根据需要扩展(在本例中为 4)?为什么这似乎是不正确的,而是使用 None?

【问题讨论】:

  • 输出的不是形状(4, 3, 7, 2)吗?
  • 它是 8,因为我为 A 低顺子添加了一张虚拟牌(最高牌 12)

标签: numpy array-broadcasting


【解决方案1】:

您正在将单个卡片结果与axis=0 叠加。因此,当移植到基于广播的解决方案时,我们可以在 4D 数组中创建这些标量 1, 2, 3, 4 的范围数组,除第一个轴外,所有轴都是单维维度(长度 = 1 的维度)。可以有不同的方法来创建这样的4D 数组。一种方法是:np.arange(1,5)[:,None,None,None],我们使用np.arange 创建一个1D 数组,然后简单地添加三个单例暗淡作为最后三个暗淡np.newaxis/None

我们将此4D 数组与b 进行相等比较,这将允许内部broadcastingb 元素沿最后三个暗淡。然后,我们将它与a 相乘,就像在原始代码中所做的那样,得到所需的输出。

因此,实现将是 -

out = a*(b == np.arange(1,5)[:,None,None,None]) 

何时/如何使用...(省略号):

当尝试将新轴添加到多维数组中时,我们使用...(省略号),并且我们不想为每个暗淡指定colons。因此,要使a 成为4D 数组,最后一个暗淡是单例,我们会这样做:a[:,:,:,None]。打字太多了!所以,我们使用... 来帮助我们:a[...,None]。请注意,无论维度数量如何,都会使用此 ... 表示法。因此,如果a 是一个5D 数组,并且要在其中添加一个新轴作为最后一个轴,我们将使用a[:,:,:,:,:,None] 或简单地使用省略号:a[...,None]。不错哦!

【讨论】:

  • 效果很好。只是想知道有没有使用 ... 符号的解决方案,但我仍然不明白何时使用它。
  • @nickpick 看看这是否有帮助 - stackoverflow.com/questions/772124/…。我们在这里不需要它,因为我们没有将新轴添加到任何 multidim 数组中。
  • 知道了:对于 3d 数组,a[...,0] 与 a[:,:,0] 相同,对于 4d,a[:,:,:,0] ,类似地,a[0,...,0] 是 a[0,:,:,0]。谢谢
  • @nickpick 在上面添加了一个部分。
  • @rayryeng 是的,我认为链接的帖子已经很好地解释了它。摘自相同:"Ellipsis is used here to indicate a placeholder for the rest of the array dimensions not specified. "。这有点像 MATLAB 使用 [] 重塑和 NumPy 对 -1 的重塑。出于同样的原因,我们不能有多个省略号。
猜你喜欢
  • 2014-05-01
  • 1970-01-01
  • 2019-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-08
  • 2016-02-07
相关资源
最近更新 更多