【问题标题】:Numpy error: shape mismatchNumpy 错误:形状不匹配
【发布时间】:2014-05-17 13:01:31
【问题描述】:

当我尝试使用 Python (Numpy) 解决科学问题时,出现“形状不匹配”错误:“形状不匹配:对象无法广播到单个形状”。我设法以更简单的形式重现了相同的错误,如下所示:

import numpy as np
nx = 3; ny = 5
ff = np.ones([nx,ny,7])
def test(x, y):
    z = 0.0
    for i in range(7):
        z = z + ff[x,y,i]
    return z

print test(np.arange(nx),np.arange(ny))

当我尝试用x=1,y=np.arange(ny) 调用test(x,y) 时,一切正常。那么这里发生了什么?为什么两个参数都不能是numpy数组?

更新

我已经通过@Saullo Castro 的一些提示解决了这个问题。以下是一些更新信息,供那些试图提供帮助但不清楚我的意图的人:

基本上,我创建了一个尺寸为 nx*ny 的网格和另一个数组 ff,它为每个节点存储了一些值。在上面的代码中,ff 每个节点有 7 个值,我试图将这 7 个值相加得到一个新的 nx*ny 数组。

但是,“形状不匹配”错误并不是由于求和过程造成的,因为你们中的许多人现在可能已经猜到了。我误解了将 ndarray 对象作为输入参数的函数的规则。我试图将np.arange(nx), np.arange(ny) 传递给test() 不会给我我想要的,即使nx==ny

回到我的初衷,我通过创建另一个函数来解决问题,并使用np.fromfunction创建了数组:

def tt(x, y):  
    return np.fromfunction(lambda a,b: test(a,b), (x, y))

这并不完美,但它确实有效。 (在这个例子中似乎不需要创建一个新函数,但是在我的实际代码中我稍微修改了它,以便它可以用于网格切片)

无论如何,与我这种肮脏的解决方案相比,我确实相信有更好的方法。因此,如果您对此有任何想法,请与我们分享:)。

【问题讨论】:

  • 我认为您误解了索引多维数组的工作原理,请查看文档;解释得很清楚docs.scipy.org/doc/numpy/user/basics.indexing.html
  • @Akavall 你能更具体一点吗?顺便说一句,我知道我正在混合使用 x[i]i,因为在这个简化的情况下它们是相同的。

标签: python arrays numpy


【解决方案1】:

让我们研究一个类似于您的ff 数组的数组:

nx = 3; ny = 4
ff = np.arange(nx*ny*5).reshape(nx,ny,5)
#array([[[ 0,  1,  2,  3,  4],
#        [ 5,  6,  7,  8,  9],
#        [10, 11, 12, 13, 14],
#        [15, 16, 17, 18, 19]],
#
#       [[20, 21, 22, 23, 24],
#        [25, 26, 27, 28, 29],
#        [30, 31, 32, 33, 34],
#        [35, 36, 37, 38, 39]],
#
#       [[40, 41, 42, 43, 44],
#        [45, 46, 47, 48, 49],
#        [50, 51, 52, 53, 54],
#        [55, 56, 57, 58, 59]]])

当您使用a, b, c 中的索引数组进行索引时,a, b, c 必须具有相同的形状,numpy 将基于索引构建一个新数组。例如:

ff[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 2, 3], [0, 0, 0, 1, 1, 1]]
#array([ 0,  5, 20, 26, 51, 56])

这被称为花式索引,就像构建一个数组:

np.array([ff[0, 0, 0], ff[0, 1, 0], ff[1, 0, 0], ..., ff[2, 3, 1]])

在您的情况下,f[x, y, i] 将产生形状不匹配错误,因为a, b, c 的形状不同。

【讨论】:

  • 谢谢索尔洛·卡斯特罗。我已经更新了我原来的帖子。请看一看。
  • @seekiu 我读到了你的更新,你可能会用ff.sum(axis=2)获得同样的结果...
  • @seekiu,如果它们符合您的需要,您会考虑接受其中一个答案...
  • 我愿意接受您的回答,因为我已经根据它解决了我的问题,尽管这并不完全符合我的要求。可惜我的声誉太低了,无法投票给别人有用的东西……无论如何,谢谢您的帮助。
【解决方案2】:

看起来您想在最后一个维度上求和 ff,第一个 2 个维度覆盖它们的整个范围。 : 用于表示一个维度的整个范围:

def test():
    z = 0.0
    for i in range(7):
        z = z + ff[:,:,i]
    return z
print test()

但是您可以通过使用sum 方法获得相同的结果而无需循环。

print ff.sum(axis=-1)

:0:n 的简写

ff[0:nx, 0:ny, 0]==ff[:,:,0]

可以使用范围索引ff 块,但您必须更加注意索引数组的形状。对于初学者来说,最好专注于让slicingbroadcasting 正确。


编辑-

您可以使用meshgrid 生成的数组来索引ff 之类的数组:

I,J = meshgrid(np.arange(nx),np.arange(ny),indexing='ij',sparse=False)
I.shape # (nx,ny)
ff[I,J,:]

也适用于

I,J = meshgrid(np.arange(nx),np.arange(ny),indexing='ij',sparse=True)
I.shape # (nx,1)
J.shape # (1, ny)

ogridmgridmeshgrid 的替代品。

【讨论】:

  • 谢谢你。我已经更新了我原来的帖子。请看一看。
  • 不知道meshgrid 生成的各种网格对你的情况有用吗?
  • 谢谢,我去看看。
【解决方案3】:

让我们在 2D 案例中重现您的问题,以便更容易看到:

import numpy as np

a = np.arange(15).reshape(3,5)

x = np.arange(3)
y = np.arange(5)

演示:

>>> a
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])
>>> a[x, y] # <- This is the error that you are getting
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: shape mismatch: objects cannot be broadcast to a single shape

# You are getting the error because x and y are different lengths,
# If x and y were the same lengths, the code would work: 

>>> a[x, x]
array([ 0,  6, 12])

# mixing arrays and scalars is not a problem

>>> a[x, 2]
array([ 2,  7, 12])

【讨论】:

  • 谢谢阿卡瓦尔。我已经更新了我原来的帖子。请看一看。
【解决方案4】:

在您的问题中不清楚您正在尝试做什么或您期望什么结果。不过,您似乎正在尝试使用变量z 计算总数。

检查sum 方法是否产生您需要的结果:

import numpy as np
nx = 3; ny = 5

ff = ff = np.array(np.arange(nx*ny*7)).reshape(nx,ny,7)

print ff.sum()          # 5460

print ff.sum(axis=0)    # array([[105, 108, 111, 114, 117, 120, 123],
                        #        [126, 129, 132, 135, 138, 141, 144],
                        #        [147, 150, 153, 156, 159, 162, 165],
                        #        [168, 171, 174, 177, 180, 183, 186],
                        #        [189, 192, 195, 198, 201, 204, 207]]) shape(5,7)

print ff.sum(axis=1)    # array([[ 70,  75,  80,  85,  90,  95, 100],
                        #        [245, 250, 255, 260, 265, 270, 275],
                        #        [420, 425, 430, 435, 440, 445, 450]]) shape (3,7)

print ff.sum(axis=2)    # array([[ 21,  70, 119, 168, 217],
                        #        [266, 315, 364, 413, 462],
                        #        [511, 560, 609, 658, 707]]) shape (3,5)

【讨论】:

  • 谢谢。我已经更新了我原来的帖子。请看一看。
猜你喜欢
  • 1970-01-01
  • 2016-05-13
  • 2019-10-20
  • 2016-12-19
  • 2015-11-06
  • 2013-04-01
  • 2018-01-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多