处理python数组中的维度崩溃

时间:2014-06-26 22:37:08

标签: python arrays numpy dimensions

使用NumPy时遇到的一个反复出现的错误是索引数组的尝试失败,因为数组的一个维度是单例,因此该维度被清除而无法编入索引。这在设计用于在任意大小的阵列上操作的功能中尤其成问题。我正在寻找最便宜,最通用的方法来避免这个错误。

以下是一个例子:

import numpy as np
f = (lambda t, u, i=0: t[:,i]*u[::-1])
a = np.eye(3)
b = np.array([1,2,3])
f(a,b)
f(a[:,0],b[1])

第一个呼叫按预期工作。第二次调用以两种方式失败:1)t无法将[:,0]编入索引,因为其形状为(3,),且2)u无法编入索引因为它是一个标量。

以下是我发现的修复:

1)在np.atleast_1d内使用np.atleast_2df等(可能有条件以确保维度的顺序正确),以确保所有参数都具有尺寸他们需要。这排除了lambdas的使用,并且可以采取我不想要的几行。

2)不要在上面写f(a[:,0],b[1]),而是使用f(a[:,[0]],b[[1]])。这很好,但我总是要记住放入额外的括号,如果索引存储在变量中,您可能不知道是否应该添加额外的括号。例如:

idx = 1
f(a[:,[0]],b[[idx]])
idx = [2,0,1]
f(a[:,[0]],b[idx])

在这种情况下,您似乎必须首先在np.atleast_1d上调用idx,这可能比将np.atleast_1d放入函数中更加麻烦。

3)在某些情况下,我可以放弃而不是放入索引。 E.g:

f = lambda t, u: t[0]*u
f(a,b)
f(a[:,0],b[0])

这很有效,并且在应用时显然是最简单的解决方案。但它在每种情况下都没有用(特别是,你的尺寸必须以正确的顺序开始)。

那么,有比上述方法更好的方法吗?

1 个答案:

答案 0 :(得分:1)

有很多方法可以避免这种行为。

首先,每当您使用np.ndarray而不是整数索引slice的维度时,输出的维度数将与输入的维度相同:

import numpy as np

x = np.arange(12).reshape(3, 4)
print x[:, 0].shape               # integer indexing
# (3,)

print x[:, 0:1].shape             # slice
# (3, 1)

这是我避免这个问题的首选方法,因为它很容易从单元素选择到多元素选择(例如x[:, i:i+1] vs x[:, i:i+n])。

正如您已经提到过的,您还可以通过使用任何整数序列来索引尺寸来避免尺寸损失:

print x[:, [0]].shape             # list
# (3, 1)

print x[:, (0,)].shape            # tuple
# (3, 1)

print x[:, np.array((0,))].shape  # array
# (3, 1)

如果您选择使用整数索引,则始终可以使用np.newaxis(或等效地None)插入新的单例维度:

print x[:, 0][:, np.newaxis]
# (3, 1)

print x[:, 0][:, None]
# (3, 1)

否则您可以手动将其重新整形为正确的大小(此处使用-1自动推断第一个尺寸的大小):

print x[:, 0].reshape(-1, 1).shape
# (3, 1)

最后,您可以使用np.matrix而不是np.ndarraynp.matrix的行为更像是MATLAB矩阵,只要您使用整数进行索引,就会保留单个维度:

y = np.matrix(x)
print y[:, 0].shape
# (3, 1)

但是,您应该知道np.matrixnp.ndarray之间存在number of other important differences,例如*运算符对数组执行元素乘法,但矩阵乘法运算矩阵。在大多数情况下,最好坚持np.ndarrays