以并行方式从数组中删除条目

3

我有一个x和y坐标的列表/数组,例如:

x = [x1, x2, x3,...]
y = [y1, y2, y3,...]

现在,我想根据条件删除特定的条目,例如以下内容:
for i in x:
    if i <= 40 and i >= -40:
        print "True"
    else:
        x.remove(i)

for i in y:
    if i <= 20 and i >=- 20:
        print "True"
    else:
        y.remove(i)

上述代码从列表中删除了相应的条目,但如果删除x1,则y1仍然保留在列表中。我想达到的目的是,如果删除x1,则还应该删除y1。我该如何做?我的最终目标是尝试绘制xy,所以当这些列表的维度不同时,无法实现此目标。我也可以使用...
zeta_list = np.column_stack((x, y))

想要得到类似于([[x1, y1], [x2, y2], [x3, y3],...]])的数组,但我不确定如何使用if条件语句来删除其中的条目。

谢谢。

5个回答

4

生成一个布尔型筛选掩码:

mask = ~((x > 40) | (x < -40) | (y > 20) | (y < -20))

然后,要从 xy 中选择值,其中 mask 为 True:

x, y = x[mask], y[mask]

x是一个NumPy数组时,(x > 40)返回一个布尔数组,形状与x相同,其中True表示x中的元素大于40。

请注意,使用|进行按位或和~进行非(布尔取反)。


另外,根据德摩根定律,您可以使用

mask = ((x <= 40) & (x >= -40) & (y <= 20) & (y >= -20))

NumPy操作是逐元素进行的。因此,只要x的一个元素在-40和40之间,且y的相应元素在-20和20之间,mask就为True。


例如:

import numpy as np
x = [-50, -50, 30, 0, 50]
y = [-30, 0, 10, 30, 40]

# change the lists to NumPy arrays
x, y = np.asarray(x), np.asarray(y)
# mask = ~((x > 40) | (x < -40) | (y > 20) | (y < -20))
mask = ((x <= 40) & (x >= -40) & (y <= 20) & (y >= -20))
x, y = x[mask], y[mask]

产量
In [35]: x
Out[35]: array([30])

In [36]: y
Out[36]: array([10])

使用

In [37]: mask
Out[37]: array([False, False,  True, False, False], dtype=bool)

我明白你在做什么,但是如果我想保留像(30,10)这样的坐标怎么办?在你的方法中,列表已经按数字顺序排序了,对吗?还是它会保留坐标?不过我真的应该试一下。 - ThunderFlash
是的,最好自己尝试一下!不过,我改变了示例以使检查结果的正确性更容易。 - unutbu

3

试试这个:

mask = ((x <= 40) & (x >= -40) & (y <= 20) & (y >= -20))
x, y = x[mask], y[mask]

NumPy会将这些操作向量化,所以它应该非常高效。
这篇博客文章可能会有所帮助,这里是np.where()的手册,其中展示了一些类似的例子。

非常感谢,有帮助! - ThunderFlash
尝试过了,但是出现了一个错误,显示TypeError: list indices must be integers, not tuple。 - ThunderFlash
啊,你的数组可能与我预期的形状或类型不同。不过没关系,很高兴能帮到你。如果你展示一下如何创建示例输入数组,我可以进行修改。但我喜欢@unutbu的答案,你应该采用它 :) - Will
1
是的,可能是原因,但这让我对np.where有了更深入的了解,我会遵循他的答案! - ThunderFlash
很抱歉,这段代码不能按照 OP 的期望工作,因为你在索引 xy 时使用了不同的方式。函数 where 的参数应该在两种情况下都是 @unutbu 提出的掩码。 - Tonechas

3
另一种选择是使用 list-comprehension 进行操作: 输入:
x = [50, 10, -50, 30, 5, 6]
y = [2, 40, 10, 5, 3, 5]

代码:

x, y = list(zip(*[(x, y) for x, y in zip(x, y) if x <= 40 and x > -40 and y <= 20 and y > -20]))

输出:

x
# (30, 5, 6)

y
# (5, 3, 5)

谢谢!学到了新东西! - ThunderFlash
对内置函数list()的调用对xy没有影响。实际上,如果你将其删除,输出的元组仍然完全相同。如果你希望xy成为列表,你应该像这样调整你的代码:x, y = map(list, zip(*[(x, y) for x, y in zip(x, y) if x <= 40 and x > -40 and y <= 20 and y > -20])) - Tonechas

1
这应该可以做到。
for i in x1:
    if i <= 40 and i >= -40:
        print "True"
        for i in y1:
            if i <=20 and i >=-20:
                print "True"
            else:
                x1.remove(i)
                y1.remove(i)
    else:
        x1.remove(i)
        y1.remove(i)

希望这有所帮助!

谢谢!


基本上我所做的就是将第二个for循环移到第一个for循环中,并在1为false时删除了两个坐标。 - Cid-El
1
我理解这个逻辑,但是当我尝试运行代码时,出现了错误:ValueError: list.remove(x): x不在list中。 - ThunderFlash
是的,我没有尝试过,里面有一些错误,我正在努力弄清楚。 - Cid-El

0
为了完整起见,这里是一个基于itertools的解决方案。
考虑以下坐标列表:
x = [-50, -50, -10,   0,  10, 50, 50, -10, -10, 0, 10, 40]
y = [-50, -20, -50,  50, -50, 20, 50, -20, -10, 0, 20, 10]

我们的目标是设置一个布尔掩码,其中在某些索引n处,x[n]y[n]位于特定区间内,值为True,否则为False。这些区间的边界为:

xmin, xmax = -40, 40
ymin, ymax = -20, 20

我们可以通过列表推导式创建这样的掩码:

mask = [xmin <= i <= xmax and ymin <= j <= ymax for (i, j) in zip(x, y)]

对于每对相应的坐标,将评估布尔表达式xmin <= i <= xmax and ymin <= j <= ymax。 如果ij都属于指定的区间,则表达式将评估为True,否则为False。在 Python 中,比较可以链接起来,使得这个布尔表达式非常简洁易读。

最后,我们可以使用函数 itertools.compress() 来摆脱那些落在限制范围之外的坐标对:

from itertools import compress
x_clipped = list(compress(x, mask))
y_clipped = list(compress(y, mask))

演示:

In [117]: mask
Out[117]: [False, False, False, False, False, False, False, True, True, True, True, True]

In [118]: x_clipped
Out[118]: [-10, -10, 0, 10, 40]

In [119]: y_clipped
Out[119]: [-20, -10, 0, 20, 10]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接