【问题标题】:Using python range objects to index into numpy arrays使用 python 范围对象索引到 numpy 数组
【发布时间】:2018-11-02 17:07:42
【问题描述】:

我以前看过一两次,但我似乎找不到任何官方文档:Using python range objects as indices in numpy。

import numpy as np
a = np.arange(9).reshape(3,3)
a[range(3), range(2,-1,-1)]
# array([2, 4, 6])

让我们触发一个索引错误,以确认范围不在合法索引方法的官方范围(双关语)内:

a['x']

# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices

现在,numpy 和它的文档之间的细微差异并非完全闻所未闻,也不一定表明某个功能不是有意的(参见例如 here)。

那么,有没有人知道为什么会这样?如果它是一个预期的功能,那么确切的语义是什么/它有什么用?是否有任何 ND 概括?

【问题讨论】:

  • 我从没见过这个;它被用于任何有信誉的图书馆吗?
  • numpy 早于 Python 3。在 Python 2 中,range(3) 是一个整数列表,numpy 将其视为“类数组”。如果 numpy 没有在 Python 3 中以向后兼容的方式处理它,那将是一团糟。
  • “那么,有没有人知道为什么会这样?” 这是一个不错的功能,非正式地称为“花式”索引,在文档中称为 @987654322 @.
  • @WarrenWeckesser 没错,上面写着(...) a non-tuple sequence object(虽然non-tuple sequence (such as a list) containing slice objects 似乎会触发基本索引)。不知道如果IndexError 没有被提出,为什么它应该挂起,但无论如何。我认为您可以将其作为答案。
  • 可能是索引尝试将np.asarray(x) 与range(3) 和[0,1,2] 一起使用。其他事情会产生错误或对象 dtype 数组。 @WarrenWeckesser,很好地说明了与 Py2 的 range 版本的兼容性。

标签: python numpy array-indexing


【解决方案1】:

不是一个正确的答案,但评论太长了。

事实上,它似乎适用于任何可索引的对象:

import numpy as np

class MyIndex:
    def __init__(self, n):
        self.n = n
    def __getitem__(self, i):
        if i < 0 or i >= self.n:
            raise IndexError
        return i
    def __len__(self):
        return self.n

a = np.array([1, 2, 3])
print(a[MyIndex(2)])
# [1 2]

我认为 NumPy 代码中的相关行在core/src/multiarray/mapping.c 中的此评论下方:

/*
 * Some other type of short sequence - assume we should unpack it like a
 * tuple, and then decide whether that was actually necessary.
 */

但我不完全确定。出于某种原因,如果您删除 if i &lt; 0 or i &gt;= self.n: raise IndexError,即使存在 __len__,它也会挂起,因此在某些时候它似乎会遍历给定对象,直到引发 IndexError。

【讨论】:

  • 它的迭代与它实际上相当慢是一致的,例如与使用aranges 的索引相比。
【解决方案2】:

只是总结一下(感谢 cmets 中的@WarrenWeckesser):实际上记录了这种行为。只需意识到range 对象是python 序列in the strict sense。

所以这只是一个花式索引的例子。但请注意,它非常缓慢:

>>> a = np.arange(100000)
>>> timeit(lambda: a[range(100000)], number=1000)
12.969507368048653
>>> timeit(lambda: a[list(range(100000))], number=1000)
7.990526253008284
>>> timeit(lambda: a[np.arange(100000)], number=1000)
0.22483703796751797

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-06
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 2021-08-29
    • 1970-01-01
    相关资源
    最近更新 更多