【问题标题】:Filter a numpy array based on largest value根据最大值过滤一个numpy数组
【发布时间】:2015-08-18 14:44:25
【问题描述】:

我有一个 numpy 数组,其中包含具有以下格式 (x, y, z, w) 的 4 维向量

数组的大小是 4 x N。现在,我拥有的数据是我拥有 (x, y, z) 空间位置的位置,而 w 在该位置保存一些特定的测量值。现在,可能有多个与 (x, y, z) 位置相关的测量值(以浮点数测量)。

我想做的是过滤数组,这样我得到一个新数组,在其中我得到与每个 (x, y, z) 位置对应的最大测量值。

所以如果我的数据是这样的:

x, y, z, w1
x, y, z, w2
x, y, z, w3

如果 w1 大于 w2 和 w3,过滤后的数据将是:

x, y, z, w1

更具体地说,假设我有如下数据:

[[ 0.7732126   0.48649481  0.29771819  0.91622924]
 [ 0.7732126   0.48649481  0.29771819  1.91622924]
 [ 0.58294263  0.32025559  0.6925856   0.0524125 ]
 [ 0.58294263  0.32025559  0.6925856   0.05 ]
 [ 0.58294263  0.32025559  0.6925856   1.7 ]
 [ 0.3239913   0.7786444   0.41692853  0.10467392]
 [ 0.12080023  0.74853649  0.15356663  0.4505753 ]
 [ 0.13536096  0.60319054  0.82018125  0.10445047]
 [ 0.1877724   0.96060999  0.39697999  0.59078612]]

这应该返回

[[ 0.7732126   0.48649481  0.29771819  1.91622924]
 [ 0.58294263  0.32025559  0.6925856   1.7 ]
 [ 0.3239913   0.7786444   0.41692853  0.10467392]
 [ 0.12080023  0.74853649  0.15356663  0.4505753 ]
 [ 0.13536096  0.60319054  0.82018125  0.10445047]
 [ 0.1877724   0.96060999  0.39697999  0.59078612]]

【问题讨论】:

  • 相同 (x,y,z) 位置的条目是否总是连续的,就像在您的示例数据中一样,还是会分散?您在实践中将有多少条目?
  • 不幸的是,他们可能分散了。他们永远不会超过 4 个。幸运的是,性能对此并不重要。
  • 仅供参考:这被称为“分组”操作(参见pandas.pydata.org/pandas-docs/stable/groupby.html)。您按前三列分组,然后将最大函数应用于组。使用 pandas (pandas.pydata.org) 等库很容易做到这一点。
  • 啊啊啊啊……我不知道熊猫。我会看看我是否能够成功使用它。感谢您的提示!

标签: python arrays numpy


【解决方案1】:

这很令人费解,但它可能和你只使用 numpy 一样好......

首先,我们使用lexsort 将具有相同坐标的所有条目放在一起。 a 是您的示例数组:

>>> perm = np.lexsort(a[:, 3::-1].T)
>>> a[perm]
array([[ 0.12080023,  0.74853649,  0.15356663,  0.4505753 ],
       [ 0.7732126 ,  0.48649481,  0.29771819,  0.91622924],
       [ 0.7732126 ,  0.48649481,  0.29771819,  1.91622924],
       [ 0.1877724 ,  0.96060999,  0.39697999,  0.59078612],
       [ 0.3239913 ,  0.7786444 ,  0.41692853,  0.10467392],
       [ 0.58294263,  0.32025559,  0.6925856 ,  0.0524125 ],
       [ 0.58294263,  0.32025559,  0.6925856 ,  0.05      ],
       [ 0.58294263,  0.32025559,  0.6925856 ,  1.7       ],
       [ 0.13536096,  0.60319054,  0.82018125,  0.10445047]])

请注意,通过反转轴,我们按x 排序,与y 断开联系,然后是z,然后是w

因为它是我们正在寻找的最大值,所以我们只需要在每个组中取最后一个条目,这是一件非常简单的事情:

>>> a_sorted = a[perm]
>>> last = np.concatenate((np.all(a_sorted[:-1, :3] != a_sorted[1:, :3], axis=1),
                           [True]))
>>> a_unique_max = a_sorted[last]
>>> a_unique_max
array([[ 0.12080023,  0.74853649,  0.15356663,  0.4505753 ],
       [ 0.13536096,  0.60319054,  0.82018125,  0.10445047],
       [ 0.1877724 ,  0.96060999,  0.39697999,  0.59078612],
       [ 0.3239913 ,  0.7786444 ,  0.41692853,  0.10467392],
       [ 0.58294263,  0.32025559,  0.6925856 ,  1.7       ],
       [ 0.7732126 ,  0.48649481,  0.29771819,  1.91622924]])

如果您不想对输出进行排序,而是按照它们在原始数组中出现的原始顺序保持它们,您也可以借助 perm

>>> a_unique_max[np.argsort(perm[last])]
array([[ 0.7732126 ,  0.48649481,  0.29771819,  1.91622924],
       [ 0.58294263,  0.32025559,  0.6925856 ,  1.7       ],
       [ 0.3239913 ,  0.7786444 ,  0.41692853,  0.10467392],
       [ 0.12080023,  0.74853649,  0.15356663,  0.4505753 ],
       [ 0.13536096,  0.60319054,  0.82018125,  0.10445047],
       [ 0.1877724 ,  0.96060999,  0.39697999,  0.59078612]])

这只会在最大程度上起作用,它是排序的副产品。如果您追求不同的功能,例如所有相同坐标条目的乘积,您可以执行以下操作:

>>> first = np.concatenate(([True],
                            np.all(a_sorted[:-1, :3] != a_sorted[1:, :3], axis=1)))
>>> a_unique_prods = np.multiply.reduceat(a_sorted, np.nonzero(first)[0])

您将不得不对这些结果进行一些尝试来组装您的返回数组。

【讨论】:

    【解决方案2】:

    我看到您已经在 cmets 中找到了指向 pandas 的指针。 FWIW,假设您不关心最终的排序顺序,因为 groupby 改变了它,这是您获得所需行为的方法。

    In [14]: arr
    Out[14]:
    array([[ 0.7732126 ,  0.48649481,  0.29771819,  0.91622924],
           [ 0.7732126 ,  0.48649481,  0.29771819,  1.91622924],
           [ 0.58294263,  0.32025559,  0.6925856 ,  0.0524125 ],
           [ 0.58294263,  0.32025559,  0.6925856 ,  0.05      ],
           [ 0.58294263,  0.32025559,  0.6925856 ,  1.7       ],
           [ 0.3239913 ,  0.7786444 ,  0.41692853,  0.10467392],
           [ 0.12080023,  0.74853649,  0.15356663,  0.4505753 ],
           [ 0.13536096,  0.60319054,  0.82018125,  0.10445047],
           [ 0.1877724 ,  0.96060999,  0.39697999,  0.59078612]])
    
    In [15]: import pandas as pd
    
    In [16]: pd.DataFrame(arr)
    Out[16]:
              0         1         2         3
    0  0.773213  0.486495  0.297718  0.916229
    1  0.773213  0.486495  0.297718  1.916229
    2  0.582943  0.320256  0.692586  0.052413
    3  0.582943  0.320256  0.692586  0.050000
    4  0.582943  0.320256  0.692586  1.700000
    5  0.323991  0.778644  0.416929  0.104674
    6  0.120800  0.748536  0.153567  0.450575
    7  0.135361  0.603191  0.820181  0.104450
    8  0.187772  0.960610  0.396980  0.590786
    
    In [17]: pd.DataFrame(arr).groupby([0,1,2]).max().reset_index()
    Out[17]:
              0         1         2         3
    0  0.120800  0.748536  0.153567  0.450575
    1  0.135361  0.603191  0.820181  0.104450
    2  0.187772  0.960610  0.396980  0.590786
    3  0.323991  0.778644  0.416929  0.104674
    4  0.582943  0.320256  0.692586  1.700000
    5  0.773213  0.486495  0.297718  1.916229
    

    【讨论】:

    • 谢谢。也很好的解决方案。我也将对此进行详细探讨。
    【解决方案3】:

    您可以从lex-sorting 输入数组开始,以连续引入具有相同前三个元素的条目。然后,创建另一个二维数组来存储最后一列条目,以便与每个重复的三元组对应的元素进入相同的行。接下来,找到这个二维数组的maxaxis=1,从而得到每个这样独特的三元组的最终max 输出。这是实现,假设A作为输入数组-

    # Lex sort A
    sortedA = A[np.lexsort(A[:,:-1].T)]
    
    # Mask of start of unique first three columns from A
    start_unqA = np.append(True,~np.all(np.diff(sortedA[:,:-1],axis=0)==0,axis=1))
    
    # Counts of unique first three columns from A
    counts = np.bincount(start_unqA.cumsum()-1)
    mask = np.arange(counts.max()) < counts[:,None]
    
    # Group A's last column into rows based on uniqueness from first three columns
    grpA = np.empty(mask.shape)
    grpA.fill(np.nan)
    grpA[mask] = sortedA[:,-1]
    
    # Concatenate unique first three columns from A and 
    # corresponding max values for each such unique triplet
    out = np.column_stack((sortedA[start_unqA,:-1],np.nanmax(grpA,axis=1)))
    

    示例运行 -

    In [75]: A
    Out[75]: 
    array([[ 1,  1,  1, 96],
           [ 1,  2,  2, 48],
           [ 2,  1,  2, 33],
           [ 1,  1,  1, 24],
           [ 1,  1,  1, 94],
           [ 2,  2,  2,  5],
           [ 2,  1,  1, 17],
           [ 2,  2,  2, 62]])
    
    In [76]: sortedA
    Out[76]: 
    array([[ 1,  1,  1, 96],
           [ 1,  1,  1, 24],
           [ 1,  1,  1, 94],
           [ 2,  1,  1, 17],
           [ 2,  1,  2, 33],
           [ 1,  2,  2, 48],
           [ 2,  2,  2,  5],
           [ 2,  2,  2, 62]])
    
    In [77]: out
    Out[77]: 
    array([[  1.,   1.,   1.,  96.],
           [  2.,   1.,   1.,  17.],
           [  2.,   1.,   2.,  33.],
           [  1.,   2.,   2.,  48.],
           [  2.,   2.,   2.,  62.]])
    

    【讨论】:

      【解决方案4】:

      您可以使用逻辑索引。

      我将以随机数据为例:

      >>> myarr = np.random.random((6, 4))
      >>> print(myarr)
      [[ 0.7732126   0.48649481  0.29771819  0.91622924]
       [ 0.58294263  0.32025559  0.6925856   0.0524125 ]
       [ 0.3239913   0.7786444   0.41692853  0.10467392]
       [ 0.12080023  0.74853649  0.15356663  0.4505753 ]
       [ 0.13536096  0.60319054  0.82018125  0.10445047]
       [ 0.1877724   0.96060999  0.39697999  0.59078612]]
      

      要获取最后一列最大的行,请执行以下操作:

      >>> greatest = myarr[myarr[:, 3]==myarr[:, 3].max()]
      >>> print(greatest)
      [[ 0.7732126   0.48649481  0.29771819  0.91622924]]
      

      它的作用是获取myarr的最后一列,并找到该列的最大值,找到该列的所有元素等于最大值,然后获取相应的行。

      【讨论】:

      • 这不是我寻求的行为。我已对问题进行了编辑,希望能更清楚。
      【解决方案5】:

      您可以使用np.argmax

      x[np.argmax(x[:,3]),:]

      >>> x = np.random.random((5,4))
      >>> x
      array([[ 0.25461146,  0.35671081,  0.54856798,  0.2027313 ],
             [ 0.17079029,  0.66970362,  0.06533572,  0.31704254],
             [ 0.4577928 ,  0.69022073,  0.57128696,  0.93995176],
             [ 0.29708841,  0.96324181,  0.78859008,  0.25433235],
             [ 0.58739451,  0.17961551,  0.67993786,  0.73725493]])
      >>> x[np.argmax(x[:,3]),:]
      array([ 0.4577928 ,  0.69022073,  0.57128696,  0.93995176])
      

      【讨论】:

      • 这不是我寻求的行为。我已对问题进行了编辑,希望能更清楚。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-09
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 2017-03-13
      • 1970-01-01
      相关资源
      最近更新 更多