Bug还是故意的:numpy针对重复的布尔索引引发“ValueError: too many boolean indices”错误

7

我正在进行一些实验宇宙学的模拟,并在使用numpy数组时遇到了这个问题。我是numpy的新手,所以不确定我是做错了还是这是一个bug。我运行了:

Enthought Python Distribution -- www.enthought.com
Version: 7.3-1 (32-bit)

Python 2.7.3 |EPD 7.3-1 (32-bit)| (default, Apr 12 2012, 11:28:34) 
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "credits", "demo" or "enthought" for more information.
>>> import numpy as np
>>> t = np.arange(10)
>>> t[t < 8][t < 5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many boolean indices
>>> 

我期望它返回:
array([0, 1, 2, 3, 4])

因为t[t < 8]应该被视为另一个ndarray?

关于布尔数组作为索引,numpy文档(http://docs.scipy.org/doc/numpy/user/basics.indexing.html)说:

与索引数组一样,返回的是数据的副本,而不是像切片一样返回视图。

运行type(t[t < 8])也会给出ndarray,我想这应该具有numpy数组的所有属性。也许我应该用列表表达式来更好地完成这个任务吗?我还没有进行定时比较,但我想对于大型2D数组来说,这可能是一个问题。


1
你期望t[t < 8][t < 5]会返回什么? - Bi Rico
抱歉,我为了更清晰明确而编辑了我的问题。 - plan
@plan - 你了解在numpy数组中,“复制”和“视图”的区别吗?术语“复制”可能会让人产生误解。一个“视图”与其父对象共享内存。“a = np.arange(10); b = a[5:]; b[0] = 42; print a”。即使它们具有不同的形状,“b”仍然是对“a”的视图。(即,改变“b”也会改变“a”)。如果我们进行类似于给出“副本”而不是“视图”的操作,那么意味着我们有一个单独的数组,它不与第一个数组共享内存。 - mgilson
不确定,但我认为现在做得更好了。视图仍然是原始数据,这使我能够执行例如 t[0:5][3:5] 这样的操作。这与我最初对副本/视图的想法完全相反。感谢 @mgilson 的观察。 - plan
2个回答

7

t[ t < 8 ]可以得到一个数组,但它所得到的数组大小不同于你原来的数组。 t < 8会返回一个布尔类型的数组,其形状与t相同。当你用布尔数组对t进行索引时,只有在布尔数组中为True的元素才被提取出来,这导致你得到了一个较短的数组。当你如此操作时:

result = t[t<8]
result[t<5]

然后,布尔索引数组再次与t具有相同的形状,但您正在使用它来索引一个较小的数组,这就是导致错误的原因。

文档完全正确。您的新数组不是原始数组的view... 它是数据的副本,但这并不意味着新数组与原始数组具有相同的形状或大小。


2
哈,看来“太多的布尔索引”并不是指您尝试使用布尔索引访问元素的次数,而是布尔索引数组的长度。 - askewchan
@askewchan -- 没错。我甚至没有考虑过以不同的方式解释回溯...也许是因为我对numpy太熟悉了。现在我明白这种困惑了。 - mgilson
对我来说,这是一个非常令人困惑的回溯,它是否有更深层次的意义还是只是令人困惑? - plan
@plan -- 对我来说很有意义。它的意思是,你的数组(t < 5)具有太多的“布尔索引”,以至于无法索引其他数组(t[ t<8 ]),因为另一个数组太小了。 - mgilson
是的,我想我只是没有想到t < 8只是一个布尔数组,因为我只使用布尔数组作为索引。 - plan

1
这是有意为之的。在第二个布尔语句中,对“t”的引用已经没有意义了。在第一个语句中,您正在通过小于8的值对“t”进行分段。在第二个语句中,您仍在对“t”进行分段,但是在临时数组(称其为“s”)上进行。对“s”的索引请求不能始终正确地映射到“t”。因此它会抛出异常。
如果您想执行多个布尔语句,请将它们合并,使其读取:
s = t[t < 8]
s[s < 5]

或者从 @mgilson 的建议中获得帮助:

(保留html标签)
t[np.logical_and(t < 8, t < 5)]

1
你不能像那样使用 and 运算符。你可以使用 np.logical_and(t<8, t<5) - mgilson
啊,那很有道理!谢谢,我应该想到了。我的问题得到了解答。我已经使用了你建议的方法。 - plan
是的,我在发布后立即尝试了它,并立即更改了它。 - Pyrce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接