【问题标题】:Pick elements in one array based on the elements of another array?根据另一个数组的元素选择一个数组中的元素?
【发布时间】:2020-03-31 21:08:29
【问题描述】:

我有 2 个 numpy 数组:数组 1 有元素 1 .. 100 表示要检查的范围(省略了最低有效数字),数组 2 有值 1 .. 1000 来检查每个范围。

import numpy
o = numpy.array([3, 7, 20, 47, 60, 72, 76, 83, 94, 94])
p = numpy.array([22, 54, 77, 83, 246, 285, 813, 828, 950, 998])

目的是获取数组 2 中在数组 1 任意范围内的元素的索引。例如,对于 22,我们需要检查:

30 < 22 < 40 => false
70 < 22 < 80 => false
etc. (all are false, so index 0 will not be in the result)

而 77 将是真的,因为它在专属范围内 &lt;70;80&gt;

什么是正确的语法?

In [238]: o
Out[238]: array([ 3,  7, 20, 47, 60, 72, 76, 83, 94, 94])

In [239]: p
Out[239]: array([ 22,  54,  77,  83, 246, 285, 813, 828, 950, 998])

In [240]: p[o*10 < p < (o+1)*10 ]

 ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

这似乎可行,但非常复杂: (与底部的绝对减法 .. 与比较值的顶部值应等于 10)

例如abs(77-60) + abs(77-70) == 10

In [329]: oo = numpy.vstack(((o*10), (o+1)*10 ) )

In [324]: ten = numpy.abs(numpy.subtract(oo[0,:],p.reshape(-1,1))) + numpy.abs(numpy.subtract(oo[1,:],p.reshape(-1,1)))

array([[  26,  106,  366,  906, 1166, 1406, 1486, 1626, 1846, 1846],
       [  38,   42,  302,  842, 1102, 1342, 1422, 1562, 1782, 1782],
       [  84,   10,  256,  796, 1056, 1296, 1376, 1516, 1736, 1736],
       [  96,   16,  244,  784, 1044, 1284, 1364, 1504, 1724, 1724],
       [ 422,  342,   82,  458,  718,  958, 1038, 1178, 1398, 1398],
       [ 500,  420,  160,  380,  640,  880,  960, 1100, 1320, 1320],
       [1556, 1476, 1216,  676,  416,  176,   96,   44,  264,  264],
       [1586, 1506, 1246,  706,  446,  206,  126,   14,  234,  234],
       [1830, 1750, 1490,  950,  690,  450,  370,  230,   10,   10],
       [1926, 1846, 1586, 1046,  786,  546,  466,  326,  106,  106]])

In [330]: numpy.where(ten == 10)
Out[330]: (array([2, 8, 8]), array([1, 8, 9]))

In [331]: p[ numpy.where(ten == 10)[0] ]
Out[331]: array([ 77, 950, 950])

【问题讨论】:

  • o 包含 94 两次。检查该范围两次有什么意义?

标签: python numpy range


【解决方案1】:

您可以使用两个掩码的交集,如下所示。但是,在您的示例中,它们的交集似乎是空的:

x = p[(o*10 < p) & (p < (o+1)*10)]

【讨论】:

  • 7 => 70 - 80 即 77 应该没问题
  • 好吧,但是 7 在 o 中的位置 2,而 77 在 p 中的位置 3。
【解决方案2】:

tl;博士

使用anymap 来做真正的工作,而不是where,它可以神奇地确定要迭代的内容,并在表达式中有多个可迭代对象时失败。

>>> numpy.where( map( lambda pval : numpy.any( (o*10 < pval) & (pval < (o+1)*10) ), p) )
(array([2]),)

长答案

比较一个数组会给出一个结果数组。目前,只应用一个范围检查:

>>> o*10 < 77
array([ True,  True, False, False, False, False, False, False, False, False], dtype=bool)

@ypnos 正确地指出了如何将其与另一个比较相结合:

>>> (o*10 < 77) & (77 < (o+1)*10)
array([False,  True, False, False, False, False, False, False, False, False], dtype=bool)

这会成对地对列表中的每个元素执行 AND 操作(如您所见,77 位于 o 的第二个元素 7 的范围内,表示70 &lt; 77 &lt; 80。但是,我们对哪个不感兴趣比较,只有其中一个成功了,所以让我们用any()折叠结果:

>>> numpy.any( (o*10 < 77) & (77 < (o+1)*10) )
True
>>> numpy.any( (o*10 < 22) & (22 < (o+1)*10) )
False

难题是如何将该操作应用于 p 的每个元素,而不是像上面那样只检查 22。 documentation for numpy.where 没有解释如何从给定的条件中选择数组,但即使将我们现有的条件包装在一个函数中并将其作为单个变量的条件调用仍然不起作用:

>>> def foo(x):
...     return numpy.any( (o*10 < x) & (x < (o+1)*10) )
...
>>> numpy.where( foo(p) )
(array([], dtype=int64),)

在这种情况下,我们实际上需要map,而不是where,它接受一个谓词和一个iterable,并将谓词(布尔函数)应用于iterable(我们之前比较和any()调用的numpy数组结果) )。结果变成:

>>> map(foo,p)
[False, False, True, False, False, False, False, False, False, False]

或者直接使用 lambda 而不是 foo 函数:

>>> map( lambda pval : numpy.any( (o*10 < pval) & (pval < (o+1)*10) ), p)
[False, False, True, False, False, False, False, False, False, False]

然后你想要索引,所以在哪里应用:

>>> numpy.where( map( lambda pval : numpy.any( (o*10 < pval) & (pval < (o+1)*10) ), p) )
(array([2]),)

【讨论】:

    猜你喜欢
    • 2013-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-08
    • 2021-10-13
    • 2020-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多