正如标题所说,假设我想写一个符号函数(让我们暂时忘记符号(0)),显然我们期望sign(2)= 1和sign(array([ - 2,-2,2]] ))= array([ - 1,-1,1])。但是,以下函数不起作用,因为它无法处理numpy数组。
def sign(x):
if x>0: return 1
else: return -1
下一个函数不起作用,因为x只有一个形状成员,如果它只是一个数字。即使使用y = x * 0 + 1这样的技巧,y也不会有[]方法。
def sign(x):
y = ones(x.shape)
y[x<0] = -1
return y
即使是另一个问题(how can I make a numpy function that accepts a numpy array, an iterable, or a scalar?)的想法,当x是单个数字时,下一个函数将不起作用,因为在这种情况下x.shape和y.shape只是()并且索引y是非法的。
def sign(x):
x = asarray(x)
y = ones(x.shape)
y[x<0] = -1
return y
唯一的解决方案似乎是首先确定x是数组还是数字,但我想知道是否有更好的东西。如果你有很多像这样的小函数,编写分支代码会很麻烦。
答案 0 :(得分:3)
np.vectorize
可以用来实现它,但是会很慢,因为当你用一个数组调用你的装饰函数时,它会循环遍历数组元素并将标量函数应用于每个元素,即不是利用numpy的速度。
我发现一个有用的矢量化函数的方法涉及if-else正在使用np.choose
:
def sign_non_zero(x):
return np.choose(
x > 0, # bool values, used as indices to the array
[
-1, # index=0=False, i.e. x<=0
1, # index=1=True, i.e. x>0
])
当x
是标量或数组时,这种方法有效,并且比在python空间中循环更快。
使用np.choose
的唯一缺点是以这种方式编写if-else逻辑并不直观,而且代码的可读性较差。当我使用它时,我会包含上述评论,以便读者更容易理解正在发生的事情。
答案 1 :(得分:2)
我想知道你想要的是 矢量化功能 :
>>> import numpy as NP
>>> def fnx(a):
if a > 0:
return 1
else:
return -1
>>> vfnx = NP.vectorize(fnx)
>>> a = NP.random.randint(1, 10, 5)
array([4, 9, 7, 9, 2])
>>> a0 = 7
>>> vfnx(a)
array([1, 1, 1, 1])
>>> vfnx(a0)
array(1)
答案 2 :(得分:1)
这是一个解决方案:
import numpy as np
def sign(x):
y = np.ones_like(x)
y[np.asarray(x) < 0] = -1
if isinstance(x, np.ndarray):
return y
else:
return type(x)(y)
这应该返回与输入相同类型的值。例如sign(42)
给出1
,sign(42.0)
给出1.0
。如果你给它一个ndarray,它将像np.sign
一样工作。
通常,您可以继续假设您的输入是ndarray。如果您尝试访问ndarray具有的属性或方法,但您的输入没有,那么您将回退到以标量类型运行。使用例外来实现这一点。例如:
def foo_on_scalars(x):
# do scalar things
def foo(x):
try:
# assume x is an ndarray
except AttributeError:
foo_on_scalars(x)
答案 3 :(得分:0)
您可以先将数字转换为单元素数组,
然后专注于对数组进行操作。
你仍然需要检查x的类型
答案 4 :(得分:0)
这是一个解决方案:
>>> def sign(x):
... if type(x)==int:
... if x>0: return 1
... else: return -1
... else:
... x=np.array(x)
... pos=np.where(x>=0)
... neg=np.where(x<0)
... res=np.zeros(x.shape[0])
... res[pos]=1
... res[neg]=-1
... return res.tolist()
...
>>> sign(56)
1
>>> sign(-556)
-1
>>> sign([23,4,-3,0,45,-3])
[1.0, 1.0, -1.0, 1.0, 1.0, -1.0]
>>> sign(np.array([23,4,-3,0,45,-3]))
[1.0, 1.0, -1.0, 1.0, 1.0, -1.0]
答案 5 :(得分:0)
我之前采用的方法很像你的上一个例子,但在开头添加额外的标量检查:
def sign(x):
if isscalar(x):
x = (x,)
x = asarray(x)
y = ones(x.shape)
y[x<0] = -1
return y
答案 6 :(得分:0)
处理标量和numpy数组的简单解决方案:
>>> import numpy as np
>>> def sign_non_zero(x):
return (x > 0) * 1 + (x < 0) * -1
>>> sign_non_zero(2)
1
>>> sign_non_zero(np.array([-2, -2, 2]))
array([-1, -1, 1])
答案 7 :(得分:0)
numpy
函数自然地处理标量或数组输入,并在输出中保留形状。因此,总是最好找到执行此工作的numpy
函数。在这种情况下,如上所述,函数应为np.sign
。对于不同的逻辑,可以使用np.where(x>0, 1, -1)
,它适用于x
的标量和数组值。