Numpy数组切片以返回切片数组和相应的数组索引

发布于 2025-02-07 21:29:40 字数 912 浏览 2 评论 0原文

我正在尝试从一个生成两个Numpy阵列。一个是原始数组的切片,另一个代表可用于查找产生的值的索引。我可以通过示例解释的最好方法是:

import numpy as np

original = np.array([
    [5, 3, 7, 3, 2],
    [8, 4, 22, 6, 4],
])

sliced_array = original[:,::3]
indices_of_slice = None # here, what command to use?

for val, idx in zip(np.nditer(sliced_array), np.nditer(indices_of_slice)):
    # I want indices_of_slice to behave the following way:
    assert val == original[idx], "Error. This implementation is not correct. "

最终我的目标是一个数组,我可以使用nditer和一个相应的数组indices_of_slices,该数组返回原始查找索引(i,j,...)。然后,切片阵列的值应等于索引中原始数组的值(i,j,...)。

主要问题是:我可以同时返回切片阵列时的新切片阵列以及值的索引吗?希望一切都很清楚!

编辑:这是两个阵列的预期打印输出:

# print(sliced_array)
# >>> [[5 3]
# >>>  [8 6]]

# expected result of 
# print(indices_of_slice)
# >>> [[(0 0) (0 3)]
# >>>  [(1 0) (1 3)]]

I'm trying to generate two numpy arrays from one. One which is a slice slice of an original array, and another which represents the indexes which can be used to look up the values produced. The best way I can explain this is by example:

import numpy as np

original = np.array([
    [5, 3, 7, 3, 2],
    [8, 4, 22, 6, 4],
])

sliced_array = original[:,::3]
indices_of_slice = None # here, what command to use?

for val, idx in zip(np.nditer(sliced_array), np.nditer(indices_of_slice)):
    # I want indices_of_slice to behave the following way:
    assert val == original[idx], "Error. This implementation is not correct. "

Ultimately what I'm aiming for is an array which I can iterate through with nditer, and a corresponding array indices_of_slices, which returns the original lookup indices (i,j,...). Then, the value of the sliced array should be equal to value of the original array in index (i,j,...).

Main question is: Can I return both the new sliced array as well as the indices of the values when slicing a numpy array? Hopefully all is clear!

Edit: Here are the expected printouts of the two arrays:

# print(sliced_array)
# >>> [[5 3]
# >>>  [8 6]]

# expected result of 
# print(indices_of_slice)
# >>> [[(0 0) (0 3)]
# >>>  [(1 0) (1 3)]]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

您可以使用numpy的slice > 带有一点点的体操,以获取您要寻找的索引:

slc = np.s_[:, ::3]

shape = original.shape
ix = np.unravel_index(np.arange(np.prod(shape)).reshape(shape)[slc], shape)

>>> ix
(array([[0, 0],
        [1, 1]]),
 array([[0, 3],
        [0, 3]]))

>>> original[ix]
array([[5, 3],
       [8, 6]])

>>> original[slc]
array([[5, 3],
       [8, 6]])

请注意,这与具有相反方向的切片作用:

slc = np.s_[:, ::-2]

# ... (as above)

>>> ix
(array([[0, 0, 0],
        [1, 1, 1]]),
 array([[4, 2, 0],
        [4, 2, 0]]))

>>> np.array_equal(original[ix], original[slc])
True

You can use numpy's slice np.s_[] with a tiny bit of gymnastics to get the indices you are looking for:

slc = np.s_[:, ::3]

shape = original.shape
ix = np.unravel_index(np.arange(np.prod(shape)).reshape(shape)[slc], shape)

>>> ix
(array([[0, 0],
        [1, 1]]),
 array([[0, 3],
        [0, 3]]))

>>> original[ix]
array([[5, 3],
       [8, 6]])

>>> original[slc]
array([[5, 3],
       [8, 6]])

Note that this works with slices that have some reverse direction:

slc = np.s_[:, ::-2]

# ... (as above)

>>> ix
(array([[0, 0, 0],
        [1, 1, 1]]),
 array([[4, 2, 0],
        [4, 2, 0]]))

>>> np.array_equal(original[ix], original[slc])
True
花落人断肠 2025-02-14 21:29:40
In [22]: original = np.array([
    ...:     [5, 3, 7, 3, 2],
    ...:     [8, 4, 22, 6, 4],
    ...: ])    
In [23]: sliced_array = original[:,::3]

制作一个带相同切片的布尔数组:

In [24]: mask = np.zeros(original.shape, dtype=bool)    
In [25]: mask[:,::3] = True    
In [26]: mask
Out[26]: 
array([[ True, False, False,  True, False],
       [ True, False, False,  True, False]])

mask选择相同的值 - 但以ravel形的形式:

In [27]: sliced_array
Out[27]: 
array([[5, 3],
       [8, 6]])

In [28]: original[mask]
Out[28]: array([5, 3, 8, 6])

我们可以从掩码中获取索引:

In [30]: idx = np.argwhere(mask)

In [31]: idx
Out[31]: 
array([[0, 0],
       [0, 3],
       [1, 0],
       [1, 3]], dtype=int64)

迭代地应用它们:

In [32]: for ij,v in zip(idx, sliced_array.ravel()):
    ...:     print(original[tuple(ij)], v)
    ...:     
5 5
3 3
8 8
6 6

用高级索引进行测试:

In [49]: aslc = ([[0],[1]], [0,2,4])

In [50]: sliced_array = original[aslc]; sliced_array
Out[50]: 
array([[ 5,  7,  2],
       [ 8, 22,  4]])

In [51]: mask = np.zeros(original.shape, dtype=bool); mask[aslc] = True; mask
Out[51]: 
array([[ True, False,  True, False,  True],
       [ True, False,  True, False,  True]])

In [52]: idx = np.argwhere(mask); idx
Out[52]: 
array([[0, 0],
       [0, 2],
       [0, 4],
       [1, 0],
       [1, 2],
       [1, 4]], dtype=int64)

In [54]: original[mask]
Out[54]: array([ 5,  7,  2,  8, 22,  4])

In [55]: for ij,v in zip(idx, sliced_array.ravel()):
    ...:     print(original[tuple(ij)], v)
    ...:     
5 5
7 7
2 2
8 8
22 22
4 4

这不是与高级索引的各种变化一起工作;例如,索引相反的订单或重复行与不匹配。

In [66]: aslc = (slice(None,None,-1),slice(3,None,-3))

In [67]: sliced_array = original[aslc]; sliced_array
Out[67]: 
array([[6, 8],
       [3, 5]])

In [68]: mask = np.zeros(original.shape, dtype=bool); mask[aslc] = True; mask
Out[68]: 
array([[ True, False, False,  True, False],
       [ True, False, False,  True, False]])

In [69]: original[mask]
Out[69]: array([5, 3, 8, 6])

mask选择相同的值,但按不同的顺序选择。

slice视图 原始的。也就是说,它使用相同的数据。但是它从不同的点开始,并使用不同的步伐。

In [70]: original.__array_interface__
Out[70]: 
{'data': (2697031319568, False),
 'strides': None,
 'descr': [('', '<i4')],
 'typestr': '<i4',
 'shape': (2, 5),
 'version': 3}

In [71]: sliced_array.__array_interface__
Out[71]: 
{'data': (2697031319600, False),
 'strides': (-20, -12),
 'descr': [('', '<i4')],
 'typestr': '<i4',
 'shape': (2, 2),
 'version': 3}

通常,numpy索引是单向街道。它创建一个具有所需值的新数组,无论是视图还是复制,但不会创建或返回映射或反向映射。除某些特殊情况外,我们无法确定在Original中找到sliced_arreay值的位置。

编辑

其他答案建议以np.s _

In [85]: np.s_[:,::3]
Out[85]: (slice(None, None, None), slice(None, None, 3))

产生切片对象的元组。他仍然必须使用arange来生成索引,因为切片本身没有oinder.shape信息。

ogrid可用于创建高级索引数组:

In [86]: idx = np.ogrid[:2,:5:3]; idx
Out[86]: 
[array([[0],
        [1]]),
 array([[0, 3]])]
In [88]: original[tuple(idx)]
Out[88]: 
array([[5, 3],
       [8, 6]])

meshgrid sparse> sparse = true提供类似的东西。或带有完全填充的数组:

In [89]: idx = np.mgrid[:2,:5:3]; idx
Out[89]: 
array([[[0, 0],
        [1, 1]],

       [[0, 3],
        [0, 3]]])

In [90]: original[tuple(idx)]
Out[90]: 
array([[5, 3],
       [8, 6]])

有多种将数组转换为(n,2)索引的方法,这些索引可以单独使用(例如我以前的代码中的arg where):

In [92]: np.transpose(idx,(1,2,0)).reshape(-1,2)
Out[92]: 
array([[0, 0],
       [0, 3],
       [1, 0],
       [1, 3]])

In [93]: for ij in _: print(original[tuple(ij)])
5
3
8
6

ix_ <ix_ < /code>是创建高级索引数组的另一种方便工具,相当于切片:

In [94]: np.ix_(np.arange(2), np.arange(0,5,3))
Out[94]: 
(array([[0],
        [1]]),
 array([[0, 3]]))

In [95]: original[_]
Out[95]: 
array([[5, 3],
       [8, 6]])

请记住,索引切片,如on ointer [:,, :: 3]产生view < /代码>。用数组索引较慢,因为它可以复制。迭代索引甚至更慢。

In [96]: mask
Out[96]: 
array([[ True, False, False,  True, False],
       [ True, False, False,  True, False]])

In [97]: np.nonzero(mask)      # aka np.where(mask)
Out[97]: (array([0, 0, 1, 1], dtype=int64), array([0, 3, 0, 3], dtype=int64))

In [98]: np.argwhere(mask)
Out[98]: 
array([[0, 0],
       [0, 3],
       [1, 0],
       [1, 3]], dtype=int64)

nonZero产生一个可直接用于索引数组的数组元组:

In [99]: original[Out[97]]
Out[99]: array([5, 3, 8, 6])

arg where给出相同的值迭代,或者有些尴尬:

In [100]: original[Out[98][:,0], Out[98][:,1]]
Out[100]: array([5, 3, 8, 6])
In [22]: original = np.array([
    ...:     [5, 3, 7, 3, 2],
    ...:     [8, 4, 22, 6, 4],
    ...: ])    
In [23]: sliced_array = original[:,::3]

Make a boolean array with the same slicing:

In [24]: mask = np.zeros(original.shape, dtype=bool)    
In [25]: mask[:,::3] = True    
In [26]: mask
Out[26]: 
array([[ True, False, False,  True, False],
       [ True, False, False,  True, False]])

mask selects the same values - but in raveled form:

In [27]: sliced_array
Out[27]: 
array([[5, 3],
       [8, 6]])

In [28]: original[mask]
Out[28]: array([5, 3, 8, 6])

We can get indices from the mask:

In [30]: idx = np.argwhere(mask)

In [31]: idx
Out[31]: 
array([[0, 0],
       [0, 3],
       [1, 0],
       [1, 3]], dtype=int64)

And iteratively apply them:

In [32]: for ij,v in zip(idx, sliced_array.ravel()):
    ...:     print(original[tuple(ij)], v)
    ...:     
5 5
3 3
8 8
6 6

Testing this with advanced indexing:

In [49]: aslc = ([[0],[1]], [0,2,4])

In [50]: sliced_array = original[aslc]; sliced_array
Out[50]: 
array([[ 5,  7,  2],
       [ 8, 22,  4]])

In [51]: mask = np.zeros(original.shape, dtype=bool); mask[aslc] = True; mask
Out[51]: 
array([[ True, False,  True, False,  True],
       [ True, False,  True, False,  True]])

In [52]: idx = np.argwhere(mask); idx
Out[52]: 
array([[0, 0],
       [0, 2],
       [0, 4],
       [1, 0],
       [1, 2],
       [1, 4]], dtype=int64)

In [54]: original[mask]
Out[54]: array([ 5,  7,  2,  8, 22,  4])

In [55]: for ij,v in zip(idx, sliced_array.ravel()):
    ...:     print(original[tuple(ij)], v)
    ...:     
5 5
7 7
2 2
8 8
22 22
4 4

This doesn't work with all variations of advanced indexing; for example, indices the reverse the order or duplicate rows won't match.

In [66]: aslc = (slice(None,None,-1),slice(3,None,-3))

In [67]: sliced_array = original[aslc]; sliced_array
Out[67]: 
array([[6, 8],
       [3, 5]])

In [68]: mask = np.zeros(original.shape, dtype=bool); mask[aslc] = True; mask
Out[68]: 
array([[ True, False, False,  True, False],
       [ True, False, False,  True, False]])

In [69]: original[mask]
Out[69]: array([5, 3, 8, 6])

mask selects the same values, but in a different order.

The slice is a view of original. That is it uses the same data. But it starts at a different point, and uses different strides.

In [70]: original.__array_interface__
Out[70]: 
{'data': (2697031319568, False),
 'strides': None,
 'descr': [('', '<i4')],
 'typestr': '<i4',
 'shape': (2, 5),
 'version': 3}

In [71]: sliced_array.__array_interface__
Out[71]: 
{'data': (2697031319600, False),
 'strides': (-20, -12),
 'descr': [('', '<i4')],
 'typestr': '<i4',
 'shape': (2, 2),
 'version': 3}

In general, numpy indexing is a one-way street. It creates a new array, whether view or copy, that has the desired values, but it does not create, or return, a mapping, or a reverse mapping. Except for some special cases, we can't identify where in original the sliced_array values are found.

edit

The other answer suggests starting with np.s_:

In [85]: np.s_[:,::3]
Out[85]: (slice(None, None, None), slice(None, None, 3))

That produces a tuple of slice objects. He still has to use arange to generate the indices, since the slices themselves don't have original.shape information.

ogrid can be used to create advanced indexing arrays:

In [86]: idx = np.ogrid[:2,:5:3]; idx
Out[86]: 
[array([[0],
        [1]]),
 array([[0, 3]])]
In [88]: original[tuple(idx)]
Out[88]: 
array([[5, 3],
       [8, 6]])

meshgrid with sparse=True gives something similar. Or with fully populated arrays:

In [89]: idx = np.mgrid[:2,:5:3]; idx
Out[89]: 
array([[[0, 0],
        [1, 1]],

       [[0, 3],
        [0, 3]]])

In [90]: original[tuple(idx)]
Out[90]: 
array([[5, 3],
       [8, 6]])

There are various ways of transforming that array into a (n,2) set of indices that could be used individually (like argwhere in my previous code):

In [92]: np.transpose(idx,(1,2,0)).reshape(-1,2)
Out[92]: 
array([[0, 0],
       [0, 3],
       [1, 0],
       [1, 3]])

In [93]: for ij in _: print(original[tuple(ij)])
5
3
8
6

ix_ is another handy tool for creating advanced indexing arrays, the equivalent of slices:

In [94]: np.ix_(np.arange(2), np.arange(0,5,3))
Out[94]: 
(array([[0],
        [1]]),
 array([[0, 3]]))

In [95]: original[_]
Out[95]: 
array([[5, 3],
       [8, 6]])

Keep in mind that indexing with slices, as in original[:,::3] produces a view. Indexing with array is slower, since it makes a copy. And iterative indexing is even slower.

In [96]: mask
Out[96]: 
array([[ True, False, False,  True, False],
       [ True, False, False,  True, False]])

In [97]: np.nonzero(mask)      # aka np.where(mask)
Out[97]: (array([0, 0, 1, 1], dtype=int64), array([0, 3, 0, 3], dtype=int64))

In [98]: np.argwhere(mask)
Out[98]: 
array([[0, 0],
       [0, 3],
       [1, 0],
       [1, 3]], dtype=int64)

nonzero produces a tuple of arrays that can be used directly to index the array:

In [99]: original[Out[97]]
Out[99]: array([5, 3, 8, 6])

argwhere gives the same values, but in a (n,2) form that has to be used iteratively, or in a somewhat awkward:

In [100]: original[Out[98][:,0], Out[98][:,1]]
Out[100]: array([5, 3, 8, 6])
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文