假设我们有以下功能:
def f(x, y):
if y == 0:
return 0
return x/y
这适用于标量值。不幸的是,当我尝试为x
和y
使用numpy数组时,比较y == 0
被视为数组操作,导致错误:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-13-9884e2c3d1cd> in <module>()
----> 1 f(np.arange(1,10), np.arange(10,20))
<ipython-input-10-fbd24f17ea07> in f(x, y)
1 def f(x, y):
----> 2 if y == 0:
3 return 0
4 return x/y
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
我尝试使用 np.vectorize
但它没有什么区别,代码仍然失败并出现相同的错误。np.vectorize
是一个选项,它给出了结果我期望的。
我能想到的唯一解决方案是在np.where
数组上使用y
,例如:
def f(x, y):
np.where(y == 0, 0, x/y)
不适用于标量。
有没有更好的方法来编写包含if语句的函数?它应该适用于标量和数组。
答案 0 :(得分:9)
一种方法是将x
和y
转换为函数内的numpy数组:
def f(x, y):
x = np.array(x)
y = np.array(y)
return np.where(y == 0, 0, x/y)
当x
或y
中的一个是标量而另一个是numpy数组时,这将起作用。如果它们都是可以广播的阵列,它也将起作用。如果它们是不兼容形状的阵列(例如,不同长度的1D阵列),它将无法工作,但不清楚在这种情况下所期望的行为是什么。
答案 1 :(得分:7)
我想知道你在np.vectorize
面临的问题是什么。它在我的系统上工作正常:
In [145]: def f(x, y):
...: if y == 0:
...: return 0
...: return x/y
In [146]: vf = np.vectorize(f)
In [147]: vf([[3],[10]], [0,1,2,0])
Out[147]:
array([[ 0, 3, 1, 0],
[ 0, 10, 5, 0]])
请注意,结果dtype
由第一个元素的结果决定。您也可以自己设置所需的输出:
In [148]: vf = np.vectorize(f, otypes=[np.float])
In [149]: vf([[3],[10]], [0,1,2,0])
Out[149]:
array([[ 0. , 3. , 1.5, 0. ],
[ 0. , 10. , 5. , 0. ]])
docs中有更多示例。
答案 2 :(得分:6)
您可以使用仅在y!=0
:
def f(x, y):
x = np.atleast_1d(np.array(x))
y = np.atleast_1d(np.ma.array(y, mask=(y==0)))
ans = x/y
ans[ans.mask]=0
return np.asarray(ans)
答案 3 :(得分:5)
一种笨重但有效的方法是基本上预处理数据:
def f(x, y):
if type(x) == int and type(y) == int: return x/y # Will it ever be used for this?
# Change scalars to arrays
if type(x) == int: x = np.full(y.shape, x, dtype=y.dtype)
if type(y) == int: y = np.full(x.shape, y, dtype=x.dtype)
# Change all divide by zero operations to 0/1
div_zero_idx = (y==0)
x[div_zero_idx] = 0
y[div_zero_idx] = 1
return x/y
我计划了所有不同的方法:
def f_mask(x, y):
x = np.ma.array(x, mask=(y==0))
y = np.array(y)
ans = x/y
ans[ans.mask]=0
return np.asarray(ans)
def f_where(x, y):
x = np.array(x)
y = np.array(y)
return np.where(y == 0, 0, x/y)
def f_vect(x, y):
if y == 0:
return 0
return x/y
vf = np.vectorize(f_vect)
print timeit.timeit('f(np.random.randint(10, size=array_length), np.random.randint(10, size=array_length))', number=10000, setup="from __main__ import f; import numpy as np; array_length=1000")
print timeit.timeit('f_mask(np.random.randint(10, size=array_length), np.random.randint(10, size=array_length))', number=10000, setup="from __main__ import f_mask; import numpy as np; array_length=1000")
print timeit.timeit('f_where(np.random.randint(10, size=array_length), np.random.randint(10, size=array_length))', number=10000, setup="from __main__ import f_where; import numpy as np; array_length=1000")
print timeit.timeit('vf(np.random.randint(10, size=array_length), np.random.randint(10, size=array_length))', number=10000, setup="from __main__ import vf; import numpy as np; array_length=(1000)")
# f
# 0.760189056396
# f_mask
# 2.24414896965
# f_where
# RuntimeWarning: divide by zero encountered in divide return np.where(y == 0, 0, x/y)
# 1.08176398277
# f_vect
# 3.45374488831
第一个功能是最快的,没有警告。如果x或y是标量,则时间比率相似。对于更高维数的阵列,掩蔽阵列方法变得相对更快(尽管它仍然是最慢的)。
答案 4 :(得分:0)
考虑到您有一个预测的vector / np数组: [0,1,0,1,1,0],您想将其转换为序列['N','Y','N','Y','Y','N']
import numpy as np
y_pred = np.array([0,1,0,1,1,0])
def toYN(x):
if x > 0:
return "Y"
else:
return "N"
vf_YN = np.vectorize(toYN)
Loan_Status = vf_YN(y_pred)
Loan_Status将包含['N','Y','N','Y','Y','N']