numpy高级索引:透明优化范围?

2024-06-09 21:55:03 发布

您现在位置:Python中文网/ 问答频道 /正文

这是受thispost启发的。你知道吗

考虑一个函数f,它返回用户通常用于索引其他数组的1d np.ndarrayidx索引。进一步假设一个频繁的结果是f返回所有合法索引。在链接的帖子中,建议使用f返回slice(None)而不是np.arange(maxind)的特殊情况。你知道吗

因为高级索引是要付出代价的

>>> a = np.arange(1_000_000)
>>> direct = lambda: np.sum(a[:])
>>> indirect = lambda: np.sum(a[a])
>>> timeit(direct, number=100)
0.07656216900795698
>>> timeit(indirect, number=100)
0.2885982050211169

乍一看,这似乎是一个合理的优化。你知道吗

不幸的是,它不是“正确的”。例如,假设用户想要创建idx的单热表示。一个简单的方法就是

result = np.zeros((k, maxind), dtype=int)
result[np.arange(k), idx] = 1

如果np.arange(maxind)slice(None)替换(它将用1填充整个result),则会中断。你知道吗

所以我的问题是:一个人能在这里吃蛋糕吗

是否有f可以返回的内容忠实地模仿np.arange(maxind)的语义,同时尽可能避免高级索引?

因为我几乎听天由命的回答是“不”:

下一个最好的是什么?

可能返回一个“增强的np.s_”,即一个具有工程__getitem__的对象?你知道吗

class smart_idx:
    def __init__(self, n):
        self.n = n
    def __getitem__(self, idx):
        idx = idx if isinstance(idx, tuple) else (idx,)
        if idx:
            count = idx.count('X')
            need_adv = count > 1
            if count == 1:
                for i in idx:
                    if not isinstance(i, slice) and i != Ellipsis:
                        need_adv = True
                        break
            repl = np.arange(self.n) if need_adv else slice(None)
            return tuple(repl if i == 'X' else i for i in idx)
        return slice(None)

用户必须像这样使用它

data[idx[3, 4:9, 'X', [1,3,2,6]]]
data[idx['X', ..., :4:-1]]
data[idx[]]

__getitem__,检测高级索引将决定在第一个示例中用np.arange(4)替换“X”,在另外两个示例中用slice(None)替换。你知道吗

但这相当笨拙,更不用说增加的开销可能会消耗掉我们获得的任何速度。你知道吗

有更简单的策略吗?


Tags: 用户selfnoneifcountnpsliceresult
1条回答
网友
1楼 · 发布于 2024-06-09 21:55:03
In [104]: x=np.arange(12).reshape(4,3)

虽然一个是副本,另一个是视图,但它们看起来是一样的:

In [107]: x[np.arange(0,4,2),:]
Out[107]: 
array([[0, 1, 2],
       [6, 7, 8]])
In [108]: x[0:4:2,:]
Out[108]: 
array([[0, 1, 2],
       [6, 7, 8]])

但是如果第二个索引是一个数组,那么arangeslice就不是替代品。你知道吗

In [109]: idx=np.array([0,2])
In [110]: x[np.arange(0,4,2),idx]
Out[110]: array([0, 8])
In [111]: x[0:4:2,idx]
Out[111]: 
array([[0, 2],
       [6, 8]])

为了匹配切片版本,我必须向arange添加一个维度。你知道吗

In [113]: x[np.ix_(np.arange(0,4,2),idx)]
Out[113]: 
array([[0, 2],
       [6, 8]])
In [114]: x[np.arange(0,4,2)[:,None],idx]
Out[114]: 
array([[0, 2],
       [6, 8]])

我不知道一个切片表达式会产生Out[110]。你知道吗

因此,除了用slice替换arange之外,我们还需要注意高级索引数组如何相互广播,以及切片意味着什么广播。你知道吗

对于3维或更多维,混合切片和高级索引变得更加复杂,如https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#combining-advanced-and-basic-indexing中所述

相关问题 更多 >