英文:
Numpy off-anti-diagonal fancy indexing
问题
以下是翻译好的部分:
这些花式索引指向矩阵的非对角线元素。元素之间的步幅也是固定的。是否有一种方法可以使用基本索引而不是花式索引来实现相同的 target
(以便返回的数组不拥有数据并且不是内存连续的),同时仍然具有可读性的代码?
英文:
Is it possible to convert the following fancy indexing to basic indexing using NumPy slices?
import numpy as np
fancy_indices = np.arange(10), 18 - np.arange(10)
source = np.arange(400).reshape(20, 20)
target = source[fancy_indices]
These fancy indices are pointing to off-anti-diagonal elements of the matrix. The stride step between elements is also fixed. Is there a way to use basic indexing, as opposed to fancy indexing, to achieve the same target
(so that the returned array does not own data and is not memory contiguous), whilst still having readable code?
答案1
得分: 1
res
是 source
的 view
,但是它是只读的:
In [54]: source[0,18]=1000
In [55]: res
Out[55]: array([1000, 37, 56, 75, 94, 113, 132, 151, 170, 189])
In [56]: res[0]=18
---------------------------------------------------------------------------
ValueError: assignment destination is read-only
查看 np.diag
的代码,我们发现它使用了 arr.flat
索引。因此,我们可以直接使用以下方式获取目标:
In [59]: source.flat[18:190:19]
Out[59]: array([1000, 37, 56, 75, 94, 113, 132, 151, 170, 189])
但是这个方式不是一个 view
。
np.diagonal
文档中提到了只读视图的部分。还演示了反对角线的用法。如果给定一个2D数组,np.diag
使用 np.diagonal
。arr.diagonal
是编译的,但 np.diag
使用 flat
技巧来创建对角线矩阵。
在评论中,我提到了使用 as_strided
。这种方法获取了10个反对角线元素,但是从19开始,而不是从18开始。但是对于这个目的,使用 flat
更容易:
In [80]: np.lib.stride_tricks.as_strided(source[:,::-1], (10,), (152,))
Out[80]: array([ 19, 38, 57, 76, 95, 114, 133, 152, 171, 190])
英文:
In [40]: target
Out[40]: array([ 18, 37, 56, 75, 94, 113, 132, 151, 170, 189])
In [48]: res = np.diagonal(source[:,::-1],1)[:10]
In [49]: res
Out[49]: array([ 18, 37, 56, 75, 94, 113, 132, 151, 170, 189])
res
is view
of source, but it's a read-only:
In [54]: source[0,18]=1000
In [55]: res
Out[55]: array([1000, 37, 56, 75, 94, 113, 132, 151, 170, 189])
In [56]: res[0]=18
---------------------------------------------------------------------------
ValueError: assignment destination is read-only
looking at the code for np.diag
, we see that it uses arr.flat
indexing. So we can get the target directly with:
In [59]: source.flat[18:190:19]
Out[59]: array([1000, 37, 56, 75, 94, 113, 132, 151, 170, 189])
This, though, is not a view
.
np.diagonal
documents the read-only view bit. Also demonstrates the anti-diagonal. np.diag
uses np.diagonal
if given a 2d array. arr.diagonal
is compiled, but np.diag
uses the flat
trick to create a diagonal matrix.
In the comment I mentioned using as_strided
. This gets 10 anti-diagonal elements, but starting with 19, rather than 18. But for this purpose flat
is easier to use.
In [80]: np.lib.stride_tricks.as_strided(source[:,::-1], (10,), (152,))
Out[80]: array([ 19, 38, 57, 76, 95, 114, 133, 152, 171, 190])
答案2
得分: 0
我认为这很困难,因为切片只能按轴执行。你可以使用生成器,这样就不会分配内存。例如像这样:
gen1 = (i for i in np.arange(10))
gen2 = (i for i in 18 - np.arange(10))
target = []
for i, j in zip(gen1, gen2):
target.append(source[i, j])
英文:
I think it is difficult, because slicing is only performed per axis. What you can do, is to use generators, which has the advantage that no memory will be allocated. For example like this:
gen1 = (i for i in np.arange(10))
gen2 = (i for i in 18 - np.arange(10))
target = []
for i,j in zip(gen1, gen2):
target.append(source[i,j])
答案3
得分: 0
受 @hpaulj 的回答启发,我认为最节省内存的方法是
np.diagonal(source[:,::-1],1)[:10]
或者
target = np.diagonal(source[:, :18-10:-1], source.shape[1] - 1 - 18)
source.flat[[18, 37]] += 100 # 这将在目标中反映出来
英文:
Inspired by @hpaulj's Answer, I think the most memory efficient ways are
np.diagonal(source[:,::-1],1)[:10]
or
target = np.diagonal(source[:, :18-10:-1], source.shape[1] - 1 - 18)
source.flat[[18, 37]] += 100 # this will be reflected in target
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论