使用'if'比较两个numpy数组的值
我对numpy数组还比较陌生,最近在比较两个数组的时候遇到了问题。
我有两个数组,内容如下:
a = np.array([1,2,3,4,5])
b = np.array([2,4,3,5,2])
我想做的事情大概是这样的:
if b > a:
c = b
else:
c = a
这样我最后得到的数组应该是c = np.array([2,4,3,5,5])。
其实可以理解为从这两个数组中每个位置取最大的值。
不过,我遇到了一个错误:
ValueError: The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all().
我试过一些方法,但不太确定这些方法是否适合我想要的结果。
有没有人能给我一些建议,帮我解决这个问题呢?
5 个回答
这可能不是最有效的方法,但这是一个更适合原问题的答案:
import numpy as np
c = np.zeros(shape=(5,1))
a = np.array([1,2,3,4,5])
b = np.array([2,4,3,5,2])
for i in range(5):
if b.item(i) > a.item(i):
c[i] = b.item(i)
else:
c[i] = a.item(i)
以下方法也可以使用:
使用
numpy.maximum
>>> np.maximum(a, b)
使用
numpy.max
和numpy.vstack
>>> np.max(np.vstack(a, b), axis = 0)
这里有另一种实现这个目标的方法
c = np.array([y if y>z else z for y,z in zip(a,b)])
在numpy中,几乎所有的比较都是逐个元素进行的,这样会返回一个完整的数组:
>>> b > a
array([ True, True, False, True, False], dtype=bool)
那么,这个结果是对还是错呢?在if
语句中应该怎么处理它呢?
numpy的做法是,它不会去猜测,而是直接抛出一个异常。
如果你想认为只要有一个值为真就算是真的,可以使用any
:
>>> if np.any(b > a): print('Yes!')
Yes!
如果你想认为只有当所有值都为真时才算是真的,可以使用all
:
>>> if np.all(b > a): print('Yes!')
不过我敢肯定你并不想用这两种方法。你想要的是对整个数组进行if
/else
的操作。
当然,你可以把单个值的if
/else
逻辑放在一个函数里,然后明确地用vectorize
它并调用:
>>> def mymax(a, b):
... if b > a:
... return b
... else:
... return a
>>> vmymax = np.vectorize(mymax)
>>> vmymax(a, b)
array([2, 4, 3, 5, 5])
这确实是个值得了解的方法……但很少有人会这样做。通常有更间接的方法可以用原生的向量化函数来实现——而且往往还有更直接的方法。
一种间接的方法是利用真和假分别对应数字1和0的事实:
>>> (b>a)*b + (b<=a)*a
array([2, 4, 3, 5, 5])
当b>a
时,这个表达式会计算1*b[i] + 0*a[i]
,而当b<=a
时,它会计算0*b[i] + 1*a[i]
。虽然有点复杂,但理解起来并不难。还有更清晰但更冗长的写法。
不过我们来找一个更好、更直接的解决方案。
首先,注意到你的mymax
函数对于两个值来说,和Python内置的max
函数是完全一样的:
>>> vmymax = np.vectorize(max)
>>> vmymax(a, b)
array([2, 4, 3, 5, 5])
然后考虑一下,对于这么有用的功能,numpy可能已经有现成的了。快速搜索一下就能找到maximum
:
>>> np.maximum(a, b)
array([2, 4, 3, 5, 5])
你在寻找一个叫做 np.fmax
的函数。这个函数的作用是比较两个数组中的每个元素,找出每对元素中较大的那个,同时会忽略掉那些是NaN(不是一个数字)的值。
import numpy as np
a = np.array([1, 2, 3, 4, 5])
b = np.array([2, 4, 3, 5, 2])
c = np.fmax(a, b)
输出结果是
array([2, 4, 3, 5, 5])