【问题标题】:Dealing with dimension collapse in python arrays处理python数组中的维度崩溃
【发布时间】:2014-06-26 22:37:08
【问题描述】:

我在使用 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) 在f 中使用np.atleast_1dnp.atleast_2d 等(可能带有条件以确保尺寸顺序正确)以确保所有参数都具有所需的尺寸。这排除了 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])

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

3) 在某些情况下,我可以侥幸不放入索引。例如:

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

这很有效,并且在应用时显然是最巧妙的解决方案。但这并不适用于所有情况(特别是,您的尺寸必须以正确的顺序开始)。

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

【问题讨论】:

  • 许多 numpy 函数都有很多行 Python 代码,这些代码在执行中心操作之前对输入进行整形和处理。例如,看看 atleast_1d 做了什么(它有 10 行长)。
  • 我感受到你的痛苦。以下是我通常处理这个问题的方式:首先我存储输入形状并检查输入是否为标量,然后应用np.atleast_1d 之类的东西并进行计算,最后我重塑结果以匹配输入形状(例如变换回到标量)。缺点:这是很多样板。好处:更灵活的界面,对调用者的惊喜更少。我认为作为您的特定领域库的一部分的相当通用的功能是值得的。

标签: python arrays numpy dimensions


【解决方案1】:

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

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

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]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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-13
    • 2015-06-05
    • 1970-01-01
    • 2013-10-28
    • 2010-12-29
    • 2019-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多