在一个numpy数组中替换负值。

107

有没有一种简单的方法将数组中所有负数替换为0?

我完全不知道如何使用NumPy数组来做到这一点。

例如:

a = array([1, 2, 3, -4, 5])

我需要返回

[1, 2, 3, 0, 5]

a < 0 得到:

[False, False, False, True, False]

我现在卡住了 - 如何使用这个数组修改原始数组。

6个回答

161

你已经完成了一半,尝试:

In [4]: a[a < 0] = 0

In [5]: a
Out[5]: array([1, 2, 3, 0, 5])

基准测试和更快的解决方案(根据我的基准测试)可以在我的回答中看到。 - Muhammad Yasirroni

100

尝试使用 numpy.clip

>>> import numpy
>>> a = numpy.arange(-10, 10)
>>> a
array([-10,  -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1,   0,   1,   2,
         3,   4,   5,   6,   7,   8,   9])
>>> a.clip(0, 10)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
您可以使用 clip(0) 仅裁剪底部一半。
>>> a = numpy.array([1, 2, 3, -4, 5])
>>> a.clip(0)
array([1, 2, 3, 0, 5])

您可以使用clip(max=n)来剪裁顶部一半的内容。(这比我的先前建议要好得多,该建议涉及将NaN传递给第一个参数并使用out来强制转换类型。)

>>> a.clip(max=2)
array([ 1,  2,  2, -4,  2])

另一个有趣的方法是使用where

>>> numpy.where(a <= 2, a, 2)
array([ 1,  2,  2, -4,  2])

最后,考虑aix的答案。我喜欢使用clip进行简单操作,因为它是自说明的,但对于更复杂的操作,他的答案更可取。


1
a.clip(0) 就足够了,因为操作者只想将负值替换为零。a.clip(0, 10) 则会排除任何大于10的值。 - Usagi
1
@Hiett - 我刚试了一下,clip仅会取一个。第一个默认为最小值。 - Usagi
可能是NumPy版本问题 - 这是我的输出:(Pdb)np.clip(w,0) *** TypeError: clip()至少需要3个参数(给出了2个)- 而:(Pdb)np.clip(w,0,1e6) array([[ 0. , 0.605]]) - bph
1
@Hiett,你用的是哪个版本的numpy?你试过使用aclip方法吗?内置函数numpy.clip给我报了同样的错误,但是方法却没有。 - senderle
如果你这样调用它,似乎可以工作,例如p w.clip(0) array([[ 0. , 0.605]]) - 多么奇怪? - bph
@senderle,我认为你正在寻找a.clip(max=2) - Bi Rico

10

另一种不使用 numpy 的极简 Python 解决方案:

[0 if i < 0 else i for i in a]

不需要定义任何额外的函数。

a = [1, 2, 3, -4, -5.23, 6]
[0 if i < 0 else i for i in a]
产生:
[1, 2, 3, 0, 0, 6]

1
很好 - 我一直在想如何将if语句放在列表推导式中的语法是什么 - 我之前把它放在for循环后面,然后只得到两个值,例如你的示例列表[0, 0]。 - bph
当我最初学习列表推导式并尝试不同的事物来测试我的理解时,我也做了同样的事情 - 对我来说,在for循环之后放置它似乎更直观。现在,然而,这样做是错误的。将其放在for之前会将其应用于列表的每个元素,将其放在之后意味着只有在满足条件时才会进入结果列表。 - Levon
2
@Hiett 这只是在列表推导式中使用三元运算符(在C中为i < 0 ? 0 : i)。加上括号可以使其更清晰:[(0 if i < 0 else i) for i in a]。将if放在后面是使用列表表达式结构的过滤器部分。[(i) for i in a if i < 0] 只会返回小于零的项目列表。 - Paul S
3
NumPy非常强大,因为它使用编译好的C代码执行许多计算,因此速度更快。与其他方法相比,我发现速度慢了近10倍(即更慢)。因此,虽然直观易读,但绝对不适用于计算密集型任务。 - rspencer

4

还有一种可能性:

In [2]: a = array([1, 2, 3, -4, 5])

In [3]: where(a<0, 0, a)
Out[3]: array([1, 2, 3, 0, 5])

2

以下是一种在Python中不使用NumPy的方法。创建一个返回所需结果的函数,使用列表推导或map函数。

>>> a = [1, 2, 3, -4, 5]

>>> def zero_if_negative(x):
...   if x < 0:
...     return 0
...   return x
...

>>> [zero_if_negative(x) for x in a]
[1, 2, 3, 0, 5]

>>> map(zero_if_negative, a)
[1, 2, 3, 0, 5]

1
曾经走过这条路,但认为一定有更简单、更适用于numpy的方法(因为我已经使用数组而不是列表了)。clip非常完美。 - bph

1

使用numpy进行基准测试:

%%timeit
a = np.random.random(1000) - 0.5
b = np.maximum(a,0)
# 18.2 µs ± 204 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%%timeit
a = np.random.random(1000) - 0.5
a[a < 0] = 0
# 19.6 µs ± 304 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%%timeit
a = np.random.random(1000) - 0.5
b = np.where(a<0, 0, a)
# 21.1 µs ± 134 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%%timeit
a = np.random.random(1000) - 0.5
b = a.clip(0)
# 37.7 µs ± 124 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

令人惊讶的是,np.maximum 赢了 @NPE 的答案


注意:

  1. os[os < 0] = 0np.where() 更快,但不支持 numba。但无论如何,np.maximum() 是我找到的最快的方法。

  2. np.maximum()np.max()np.amax() 不同。 np.maximum() 可以将 向量 与单个值进行比较。


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