如何根据多个条件从numpy数组中删除行?

11

我有一个拥有数千行的三列文件。我想删除那些第一列项目在特定范围内的行。例如,如果我的文件中的数据如下:

18  6.215   0.025
19  6.203   0.025
20  6.200   0.025
21  6.205   0.025
22  6.201   0.026
23  6.197   0.026
24  6.188   0.024
25  6.187   0.023
26  6.189   0.021
27  6.188   0.020
28  6.192   0.019
29  6.185   0.020
30  6.189   0.019
31  6.191   0.018
32  6.188   0.019
33  6.187   0.019
34  6.194   0.021
35  6.192   0.024
36  6.193   0.024
37  6.187   0.026
38  6.184   0.026
39  6.183   0.027
40  6.189   0.027

我想要移除那些第一个项目在20和25之间或者30和35之间的行。期望的输出如下:

18  6.215   0.025
19  6.203   0.025
26  6.189   0.021
27  6.188   0.020
28  6.192   0.019
29  6.185   0.020
36  6.193   0.024
37  6.187   0.026
38  6.184   0.026
39  6.183   0.027
40  6.189   0.027

我该如何做到这一点?

4个回答

14

如果你想继续使用numpy,解决方案并不困难。

data = data[np.logical_not(np.logical_and(data[:,0] > 20, data[:,0] < 25))]
data = data[np.logical_not(np.logical_and(data[:,0] > 30, data[:,0] < 35))]
如果你想将所有内容合并为一个语句,
data = data[
    np.logical_not(np.logical_or(
        np.logical_and(data[:,0] > 20, data[:,0] < 25),
        np.logical_and(data[:,0] > 30, data[:,0] < 35)
    ))
]

简单来说,类似 data[:,0] < 25 的条件语句会创建布尔数组,逐个元素跟踪数组中条件的真假。在此情况下,它告诉你数据的第一列小于25的位置。

你还可以使用这些布尔数组索引numpy数组。如 data[data[:,0] > 30] 这样的语句提取所有行,其中 data[:,0] > 30 为真,或者第一个元素大于30的所有行。这种条件索引就是你提取所需行(或列、或元素)的方法。

最后,我们需要逻辑工具以逐个元素地组合布尔数组。常规的 andornot 语句不能用,因为它们试图将布尔数组整体组合在一起。幸运的是,numpy提供了一组这些工具,可通过 np.logical_andnp.logical_ornp.logical_not 使用。有了这些,我们可以逐个元素地组合我们的布尔数组,以找到满足更复杂条件的行。


2
或者您可以这样做 col0=a[:,0]a[~((col0>=20) & (col0<=25) & (col0>=30) & (col0<=35))] - Saullo G. P. Castro

3
以下是我对从numpy数组中删除特定行的问题的解决方案。解决方案以一行代码的形式提供,如下所示:
#  Remove the rows whose first item is between 20 and 25
A = np.delete(A, np.where( np.bitwise_and( (A[:,0]>=20), (A[:,0]<=25) ) )[0], 0)

并且基于纯numpy函数(np.bitwise_and, np.where, np.delete)实现。
A = np.array( [   [ 18, 6.215, 0.025 ],
    [ 19, 6.203, 0.025 ],
    [ 20, 6.200, 0.025 ],
    [ 21, 6.205, 0.025 ],
    [ 22, 6.201, 0.026 ],
    [ 23, 6.197, 0.026 ],
    [ 24, 6.188, 0.024 ],
    [ 25, 6.187, 0.023 ],
    [ 26, 6.189, 0.021 ],
    [ 27, 6.188, 0.020 ],
    [ 28, 6.192, 0.019 ],
    [ 29, 6.185, 0.020 ],
    [ 30, 6.189, 0.019 ],
    [ 31, 6.191, 0.018 ],
    [ 32, 6.188, 0.019 ],
    [ 33, 6.187, 0.019 ],
    [ 34, 6.194, 0.021 ],
    [ 35, 6.192, 0.024 ],
    [ 36, 6.193, 0.024 ],
    [ 37, 6.187, 0.026 ],
    [ 38, 6.184, 0.026 ],
    [ 39, 6.183, 0.027 ],
    [ 40, 6.189, 0.027 ] ] )

#  Remove the rows whose first item is between 20 and 25
A = np.delete(A, np.where( np.bitwise_and( (A[:,0]>=20), (A[:,0]<=25) ) )[0], 0)

# Remove the rows whose first item is between 30 and 35
A = np.delete(A, np.where( np.bitwise_and( (A[:,0]>=30), (A[:,0]<=35) ) )[0], 0)

>>> A
array([[  1.80000000e+01,   6.21500000e+00,   2.50000000e-02],
       [  1.90000000e+01,   6.20300000e+00,   2.50000000e-02],
       [  2.60000000e+01,   6.18900000e+00,   2.10000000e-02],
       [  2.70000000e+01,   6.18800000e+00,   2.00000000e-02],
       [  2.80000000e+01,   6.19200000e+00,   1.90000000e-02],
       [  2.90000000e+01,   6.18500000e+00,   2.00000000e-02],
       [  3.60000000e+01,   6.19300000e+00,   2.40000000e-02],
       [  3.70000000e+01,   6.18700000e+00,   2.60000000e-02],
       [  3.80000000e+01,   6.18400000e+00,   2.60000000e-02],
       [  3.90000000e+01,   6.18300000e+00,   2.70000000e-02],
       [  4.00000000e+01,   6.18900000e+00,   2.70000000e-02]])

A = np.delete(A, np.nonzero( np.bitwise_and( (A[:,0]>=20), (A[:,0]<=25) ) )[0], 0) 可以得到相同的结果,如果使用 np.nonzero 替换 np.where。在文档中推荐使用 np.nonzero,如果在 np.where 中没有给出所有三个参数。 - Tirtha R

2
在特殊但频繁的情况下,选择标准是值是否落在一个区间内时,我使用到中点的差的abs(),特别是如果midInterval具有物理含义:
data = data[abs(data[:,0] - midInterval) < deviation] # '<' for keeping the interval

如果数据类型是整形且中值不变(如Jun的请求),您可以将其乘以二,而无需将其转换为浮点数(对于大整数,四舍五入误差会变得> 1):

data = data[abs(2*data[:,0] - sumOfLimits) > deltaOfLimits]

重复操作以删除两个区间。根据Jun的问题中给出的限制:
data = data[abs(2*data[:,0] - 45) > 3]
data = data[abs(2*data[:,0] - 65) > 3]

-1

你不需要使用numpy增加复杂性。 我猜你在这里将文件读入一个列表的列表中(每一行都是数据列表中的一个列表,像这样:((18, 6.215, 0.025), (19, 6.203, 0.025), ...))。 在这种情况下,请使用以下规则:

for row in data:
    if((row[0] > 20 and row[0] < 25) or (row[0] > 30 and row[0] < 35)):
        data.remove(row)

我使用loadtxt()从文件中读取数据。如果我使用readlines()来读取它们,每个项目都会变成字符串类型,那么我该如何处理它们呢? - Jun

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