【问题标题】:Indices of unique values in n-dimensional arrayn维数组中唯一值的索引
【发布时间】:2019-02-17 15:07:16
【问题描述】:

我有一个 2D Numpy 数组,其中包含从 0 到 n 的值。 我想得到一个长度为 n 的列表,这样该列表的第 i 个元素是一个包含所有值为 i+1 的索引的数组(不包括 0)。

例如,对于输入

array([[1, 0, 1],
   [2, 2, 0]])

我期待得到

[array([[0, 0], [0, 2]]), array([[1,0], [1,1]])]

我发现了这个相关的问题: Get a list of all indices of repeated elements in a numpy array 这可能会有所帮助,但我希望找到一个更直接的解决方案,不需要对数组进行展平和排序,并且尽可能高效。

【问题讨论】:

  • 您的预期结果是一个不同大小的数组列表。没有“直接”的方式。在拒绝之前研究链接的答案。
  • @hpaulj:正是我的观点。问题中提出了过多的自定义。并且所需的输出已经是一个列表
  • 您打算以“直接”和“高效”的方式使用结果列表吗?

标签: python arrays numpy


【解决方案1】:

这是一种矢量化方法,适用于任意维数的数组。这个解决方案的想法是在np.unique 中扩展return_index 方法的功能,并返回一个数组数组,每个数组包含一个numpy 数组中唯一值的N 维索引。

为了更紧凑的解决方案,我定义了以下函数以及在不同步骤中的一些解释:

def ndix_unique(x):
    """
    Returns an N-dimensional array of indices
    of the unique values in x
    ----------
    x: np.array
       Array with arbitrary dimensions
    Returns
    -------
    - 1D-array of sorted unique values
    - Array of arrays. Each array contains the indices where a
      given value in x is found
    """
    x_flat = x.ravel()
    ix_flat = np.argsort(x_flat)
    u, ix_u = np.unique(x_flat[ix_flat], return_index=True)
    ix_ndim = np.unravel_index(ix_flat, x.shape)
    ix_ndim = np.c_[ix_ndim] if x.ndim > 1 else ix_flat
    return u, np.split(ix_ndim, ix_u[1:])

检查问题中的数组 -

a = np.array([[1, 0, 1],[2, 2, 0]])

vals, ixs = ndix_unique(a)

print(vals)
array([0, 1, 2])

print(ixs)
[array([[0, 1],
        [1, 2]]), 
 array([[0, 0],
        [0, 2]]), 
 array([[1, 0],
        [1, 1]])]

让我们试试这个另一种情况:

a = np.array([[1,1,4],[2,2,1],[3,3,1]])

vals, ixs = ndix_unique(a)

print(vals)
array([1, 2, 3, 4])

print(ixs)
array([array([[0, 0],
              [0, 1],
              [1, 2],
              [2, 2]]),
       array([[1, 0],
              [1, 1]]), 
       array([[2, 0],
              [2, 1]]),
       array([[0, 2]])], dtype=object)

对于 1D 数组:

a = np.array([1,5,4,3,3])

vals, ixs = ndix_unique(a)

print(vals)
array([1, 3, 4, 5])

print(ixs)
array([array([0]), array([3, 4]), array([2]), array([1])], dtype=object)

最后是另一个带有 3D ndarray 的示例:

a = np.array([[[1,1,2]],[[2,3,4]]])

vals, ixs = ndix_unique(a)

print(vals)
array([1, 2, 3, 4])

print(ixs)
array([array([[0, 0, 0],
              [0, 0, 1]]),
       array([[0, 0, 2],
              [1, 0, 0]]), 
       array([[1, 0, 1]]),
       array([[1, 0, 2]])], dtype=object)

【讨论】:

  • 啊,是的@Bazingaa,但请注意我需要同时使用y 和它的扁平化版本。所以扁平化不是为了获取唯一值
  • 有时return_indexreturn_inverseunique 很有用。
  • 嗨@kontradictos。别客气!我正在简化代码并更改一些内容。这背后的原因是它改编自其他一些函数,该函数考虑到无法对唯一值向量(此处为 x)进行排序。情况并非如此。几分钟后更新
  • @hpaulj 感谢您的建议顺便说一句,帮助简化了我的代码:-)
【解决方案2】:

您可以先获取数组中的非零元素,然后在列表推导中使用argwhere 为每个非零元素获取单独的数组。这里np.unique(arr[arr!=0]) 将为您提供非零元素,您可以在这些元素上进行迭代以获取索引。

arr = np.array([[1, 0, 1],
            [2, 2, 0]])

indices = [np.argwhere(arr==i) for i in np.unique(arr[arr!=0])]
# [array([[0, 0],
#         [0, 2]]), array([[1, 0],
#         [1, 1]])]

【讨论】:

  • 这样我无法知道索引是属于值1还是2。我想得到两个索引列表,每个非零值一个。
  • 是的,这里没有对应于数组中的不同值。它只返回大于 0 的坐标,而不管它们的值如何
  • @yatu:检查我编辑的答案。感谢您的评论
  • @kontradictos:我根据您的需求修改了答案
  • 现在是的,在这里避免 for 循环并不容易 :-)
猜你喜欢
  • 2018-07-16
  • 2017-08-03
  • 2016-09-19
  • 2018-09-18
  • 1970-01-01
  • 2020-11-12
  • 1970-01-01
相关资源
最近更新 更多