import numpy as np
data = np.array([
[20, 0, 5, 1],
[20, 0, 5, 1],
[20, 0, 5, 0],
[20, 1, 5, 0],
[20, 1, 5, 0],
[20, 2, 5, 1],
[20, 3, 5, 0],
[20, 3, 5, 0],
[20, 3, 5, 1],
[20, 4, 5, 0],
[20, 4, 5, 0],
[20, 4, 5, 0]
])
我有以下二维数组。让我们按上述顺序调用字段 a、b、c、d
,其中 b
列类似于 id
。我希望删除所有在 d
列中没有 atlist 1 出现数字“1”的单元格,因为 b
列中具有相同数字的所有单元格(相同的 id)所以过滤后我将得到以下结果:
[[20 0 5 1]
[20 0 5 1]
[20 0 5 0]
[20 2 5 1]
[20 3 5 0]
[20 3 5 0]
[20 3 5 1]]
所有具有b = 1
和b = 4
的行都已从数据中删除
总结一下,因为我看到不合适的答案。我们通过 b
列查看数据 block 。如果一个完整的数据 block 在 d
列中甚至没有一次出现数字“1”,我们将删除该 b
项的所有行。在下面的示例中,我们可以看到具有 0 次出现的 b = 1
和 b = 4
(“id”= 1 和“id”= 4)的数据 block d
列中的数字“1”。这就是它从数据中删除的原因
最佳答案
通用方法:这是一种使用 np.unique
的方法和 np.bincount
解决一般情况 -
unq,tags = np.unique(data[:,1],return_inverse=1)
goodIDs = np.flatnonzero(np.bincount(tags,data[:,3]==1)>=1)
out = data[np.in1d(tags,goodIDs)]
sample 运行-
In [15]: data
Out[15]:
array([[20, 10, 5, 1],
[20, 73, 5, 0],
[20, 73, 5, 1],
[20, 31, 5, 0],
[20, 10, 5, 1],
[20, 10, 5, 0],
[20, 42, 5, 1],
[20, 54, 5, 0],
[20, 73, 5, 0],
[20, 54, 5, 0],
[20, 54, 5, 0],
[20, 31, 5, 0]])
In [16]: out
Out[16]:
array([[20, 10, 5, 1],
[20, 73, 5, 0],
[20, 73, 5, 1],
[20, 10, 5, 1],
[20, 10, 5, 0],
[20, 42, 5, 1],
[20, 73, 5, 0]])
具体情况做法:如果第二列数据一直是排序的,并且有从0
开始的序号,我们可以使用简化版,像这样-
goodIDs = np.flatnonzero(np.bincount(data[:,1],data[:,3]==1)>=1)
out = data[np.in1d(data[:,1],goodIDs)]
sample 运行-
In [44]: data
Out[44]:
array([[20, 0, 5, 1],
[20, 0, 5, 1],
[20, 0, 5, 0],
[20, 1, 5, 0],
[20, 1, 5, 0],
[20, 2, 5, 1],
[20, 3, 5, 0],
[20, 3, 5, 0],
[20, 3, 5, 1],
[20, 4, 5, 0],
[20, 4, 5, 0],
[20, 4, 5, 0]])
In [45]: out
Out[45]:
array([[20, 0, 5, 1],
[20, 0, 5, 1],
[20, 0, 5, 0],
[20, 2, 5, 1],
[20, 3, 5, 0],
[20, 3, 5, 0],
[20, 3, 5, 1]])
此外,如果 data[:,3]
总是有 1 和 0,我们可以只使用 data[:,3]
代替 data[ :,3]==1
在上面列出的代码中。
基准测试
让我们针对更大数组的特定情况对矢量化方法进行基准测试 -
In [69]: def logical_or_based(data): #@ Eric's soln
...: b_vals = data[:,1]
...: d_vals = data[:,3]
...: is_ok = np.zeros(np.max(b_vals) + 1, dtype=np.bool_)
...: np.logical_or.at(is_ok, b_vals, d_vals)
...: return is_ok[b_vals]
...:
...: def in1d_based(data):
...: goodIDs = np.flatnonzero(np.bincount(data[:,1],data[:,3])!=0)
...: out = np.in1d(data[:,1],goodIDs)
...: return out
...:
In [70]: # Setup input
...: data = np.random.randint(0,100,(10000,4))
...: data[:,1] = np.sort(np.random.randint(0,100,(10000)))
...: data[:,3] = np.random.randint(0,2,(10000))
...:
In [71]: %timeit logical_or_based(data) #@ Eric's soln
1000 loops, best of 3: 1.44 ms per loop
In [72]: %timeit in1d_based(data)
1000 loops, best of 3: 528 µs per loop
关于python通过一大块数据过滤二维数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40132352/