我有一个形状为[120000,3]的数组,其中只有前1500个元素有用,其他元素为0。
这里有个例子
[15.0, 14.0, 13.0]
[11.0, 7.0, 8.0]
[4.0, 1.0, 3.0]
[0.0, 0.0, 0.0]
[0.0, 0.0, 0.0]
[0.0, 0.0, 0.0]
[0.0, 0.0, 0.0]
我必须找到一种方法来删除所有[0.0,0.0,0.0]的元素。我试图写这个,但是没用
for point in points:
if point[0] == 0.0 and point[1] == 0.0 and point[2] == 0.0:
np.delete(points, point)
修改
评论中的所有解决方案都有效,但是我在我所使用的解决方案上打了绿色勾。谢谢大家。
答案 0 :(得分:6)
不要用于循环-循环很慢。在for循环中重复调用np.delete
会导致性能下降。
相反,创建一个遮罩:
zero_rows = (points == 0).all(1)
这是一个长度为120000的数组,在该行中所有元素均为0的情况下为True。
然后找到第一行:
first_invalid = np.where(zero_rows)[0][0]
最后,对数组进行切片:
points[:first_invalid]
答案 1 :(得分:4)
有几种相关方法,分为两个阵营。您可以通过计算单个布尔数组和np.ndarray.all
来使用矢量化方法。或者,您可以通过0
循环或带有生成器表达式的for
来计算仅包含next
元素的第一行的索引。
为了提高性能,建议您将numba
与手动for
循环一起使用。这是一个示例,但请参阅下面的基准测试,以获取更有效的变体:
from numba import jit
@jit(nopython=True)
def trim_enum_nb(A):
for idx in range(A.shape[0]):
if (A[idx]==0).all():
break
return A[:idx]
# python 3.6.5, numpy 1.14.3
%timeit trim_enum_loop(A) # 9.09 ms
%timeit trim_enum_nb(A) # 193 µs
%timeit trim_enum_nb2(A) # 2.2 µs
%timeit trim_enum_gen(A) # 8.89 ms
%timeit trim_vect(A) # 3.09 ms
%timeit trim_searchsorted(A) # 7.67 µs
设置
import numpy as np
from numba import jit
np.random.seed(0)
n = 120000
k = 1500
A = np.random.randint(1, 10, (n, 3))
A[k:, :] = 0
功能
def trim_enum_loop(A):
for idx, row in enumerate(A):
if (row==0).all():
break
return A[:idx]
@jit(nopython=True)
def trim_enum_nb(A):
for idx in range(A.shape[0]):
if (A[idx]==0).all():
break
return A[:idx]
@jit(nopython=True)
def trim_enum_nb2(A):
for idx in range(A.shape[0]):
res = False
for col in range(A.shape[1]):
res |= A[idx, col]
if res:
break
return A[:idx]
def trim_enum_gen(A):
idx = next(idx for idx, row in enumerate(A) if (row==0).all())
return A[:idx]
def trim_vect(A):
idx = np.where((A == 0).all(1))[0][0]
return A[:idx]
def trim_searchsorted(A):
B = np.frombuffer(A, 'S12')
idx = A.shape[0] - np.searchsorted(B[::-1], B[-1:], 'right')[0]
return A[:idx]
检查
# check all results are the same
assert (trim_vect(A) == trim_enum_loop(A)).all()
assert (trim_vect(A) == trim_enum_nb(A)).all()
assert (trim_vect(A) == trim_enum_nb2(A)).all()
assert (trim_vect(A) == trim_enum_gen(A)).all()
assert (trim_vect(A) == trim_searchsorted(A)).all()
答案 2 :(得分:2)
y = [i for i in x if i != [0.0, 0.0, 0.0]]
简单的迭代解决方案:
y = list(filter(lambda a: a != [0.0, 0.0, 0.0], x))
更好的解决方案(Python 3.x):
[[15.0, 14.0, 13.0], [11.0, 7.0, 8.0], [4.0, 1.0, 3.0]]
输出:
ANTLR
答案 3 :(得分:2)
知道这已经结束了,只是以为我会给出我的答案:)
x = [[15.0, 14.0, 13.0],
[11.0, 7.0, 8.0],
[4.0, 1.0, 3.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0]]
然后可以进行语义列表理解
[i for i in x if all(i)]
并输出:
[[15.0, 14.0, 13.0],[11.0, 7.0, 8.0],[4.0, 1.0, 3.0]]
需要
0.0000010866 # seconds or 1.0866 microseconds
花一点时间撒盐,这确实让我花了2秒钟来获得更好的估计
何时:
x = [[15.0, 14.0, 13.0],
[11.0, 7.0, 8.0],
[4.0, 1.0, 3.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0]]*(120000//7)
我有时间
0.01199 # seconds
这次很大程度上取决于他们是否为0,因为忽略它,所以0的速度要快得多。
答案 4 :(得分:2)
对于对数复杂度,可以在按行强制转换数据后使用numpy.searchsorted:
B=np.frombuffer(A,'S12')
index=B.size-np.searchsorted(B[::-1],B[-1:],'right')[0]
index
将是第一个都不为空的非空项目的数量。
测试:
>>>> %timeit B.size-searchsorted(B[::-1],B[-1:],'right')[0]
2.2 µs
答案 5 :(得分:1)
使用vstack
的简单迭代解决方案import numpy as np
b = np.empty((0,3), float)
for elem in a:
toRemove = np.array([0.0, 0.0, 0.0])
if(not np.array_equal(elem,toRemove)):
b=np.vstack((b, elem))