有没有if子句可以执行以下操作的方法?
我正在阅读一组带有pupynere的netcdf文件,并希望构建一个带有numpy追加的数组。有时输入数据是多维的(见下面的变量“a”),有时是一维(“b”),但第一维中的元素数总是相同的(下例中的“9”)。
> import numpy as np
> a = np.arange(27).reshape(3,9)
> b = np.arange(9)
> a.shape
(3, 9)
> b.shape
(9,)
这可以按预期工作:
> np.append(a,a, axis=0)
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],
[ 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]])
但是,附加b不能如此优雅地工作:
> np.append(a,b, axis=0)
ValueError: arrays must have same number of dimensions
追加的问题是(来自numpy手册)
"When axis is specified, values must have the correct shape."
为了得到正确的结果,我必须先施展。
> np.append(a,b.reshape(1,9), axis=0)
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],
[ 0, 1, 2, 3, 4, 5, 6, 7, 8]])
所以,在我的文件读取循环中,我正在使用这样的if子句:
for i in [a, b]:
if np.size(i.shape) == 2:
result = np.append(result, i, axis=0)
else:
result = np.append(result, i.reshape(1,9), axis=0)
有没有办法在没有if语句的情况下附加“a”和“b”?
编辑:虽然@Sven完美地回答了原始问题(使用np.atleast_2d()
),但他(和其他人)指出代码效率低下。在下面的答案中,我结合了他们的建议并替换了我的原始代码。它现在应该更有效率。感谢。
答案 0 :(得分:3)
您可以使用numpy.atleast_2d()
:
result = np.append(result, np.atleast_2d(i), axis=0)
那就是说,注意重复使用numpy.append()
是构建NumPy数组的一种非常低效的方法 - 它必须在每一步中重新分配。如果可能的话,使用所需的最终大小预先分配数组,然后使用切片填充它。
答案 1 :(得分:2)
您可以将所有数组添加到列表中,然后使用np.vstack()
在最后将它们连接在一起。这避免了每次追加时不断重新分配不断增长的数组。
|1> a = np.arange(27).reshape(3,9)
|2> b = np.arange(9)
|3> np.vstack([a,b])
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],
[ 0, 1, 2, 3, 4, 5, 6, 7, 8]])
答案 2 :(得分:1)
我将在@Sven,@ Henry和@Robert的帮助下改进我的代码。 @Sven回答了这个问题,所以他赢得了这个问题的声誉,但是 - 正如他和其他人所强调的那样 - 这是一种更有效的方式来做我想做的事。
这涉及使用python列表,允许附加performance penalty of O(1) whereas numpy.append() has a performance penalty of O(N**2)。之后,列表将转换为numpy数组:
假设i
属于a
或b
类型:
> a = np.arange(27).reshape(3,9)
> b = np.arange(9)
> a.shape
(3, 9)
> b.shape
(9,)
初始化列表并附加所有读取数据,例如如果数据按'aaba'的顺序出现。
> mList = []
> for i in [a,a,b,a]:
mList.append(i)
您的mList
将如下所示:
> mList
[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]]),
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]]),
array([0, 1, 2, 3, 4, 5, 6, 7, 8]),
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]])]
最后,vstack
列表形成一个numpy数组:
> result = np.vstack(mList[:])
> result.shape
(10, 9)
再次感谢您提供宝贵的帮助。
答案 3 :(得分:0)
正如所指出的,追加需要重新分配每个numpy数组。分配一次的替代解决方案是这样的:
total_size = 0
for i in [a,b]:
total_size += i.size
result = numpy.empty(total_size, dtype=a.dtype)
offset = 0
for i in [a,b]:
# copy in the array
result[offset:offset+i.size] = i.ravel()
offset += i.size
# if you know its always divisible by 9:
result = result.reshape(result.size//9, 9)
如果你不能预先计算数组大小,那么也许你可以在大小上加上一个上限,然后只预先分配一个总是足够大的块。然后,您可以将结果视为该块的视图:
result = result[0:known_final_size]