从数组中删除所有零

时间:2018-09-09 10:50:04

标签: python arrays python-2.7 numpy

我有一个形状为[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)

修改

评论中的所有解决方案都有效,但是我在我所使用的解决方案上打了绿色勾。谢谢大家。

6 个答案:

答案 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))