首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >当函数包含条件时,使用Numpy将函数应用于数组

当函数包含条件时,使用Numpy将函数应用于数组
EN

Stack Overflow用户
提问于 2018-12-03 21:21:31
回答 3查看 416关注 0票数 0

当函数包含条件时,我在将函数应用于数组时遇到了困难。我有一个低效的变通办法,正在寻找一种有效(快速)的方法。举个简单的例子:

代码语言:javascript
复制
pts = np.linspace(0,1,11)
def fun(x, y):
    if x > y:
        return 0
    else:
        return 1

现在,如果我运行:

代码语言:javascript
复制
result = fun(pts, pts)

然后我得到了错误

ValueError:包含多个元素的数组的真值不明确。使用a.any()或a.all()

if x > y生产线上长大。我的低效变通方法,给出正确的结果,但速度太慢:

代码语言:javascript
复制
result = np.full([len(pts)]*2, np.nan)
for i in range(len(pts)):
    for j in range(len(pts)):
        result[i,j] = fun(pts[i], pts[j])

以更好(更重要的是,更快)的方式获得它的最好方法是什么?

当函数包含条件时,我在将函数应用于数组时遇到了困难。我有一个低效的变通办法,正在寻找一种有效(快速)的方法。举个简单的例子:

代码语言:javascript
复制
pts = np.linspace(0,1,11)
def fun(x, y):
    if x > y:
        return 0
    else:
        return 1

现在,如果我运行:

代码语言:javascript
复制
result = fun(pts, pts)

然后我得到了错误

ValueError:包含多个元素的数组的真值不明确。使用a.any()或a.all()

if x > y生产线上长大。我的低效变通方法,给出正确的结果,但速度太慢:

代码语言:javascript
复制
result = np.full([len(pts)]*2, np.nan)
for i in range(len(pts)):
    for j in range(len(pts)):
        result[i,j] = fun(pts[i], pts[j])

以更好(更重要的是,更快)的方式获得它的最好方法是什么?

编辑:使用

代码语言:javascript
复制
def fun(x, y):
    if x > y:
        return 0
    else:
        return 1
x = np.array(range(10))
y = np.array(range(10))
xv,yv = np.meshgrid(x,y)
result = fun(xv, yv)  

仍然会引发相同的ValueError

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-12-03 21:25:34

这个错误是非常明显的-假设您有

代码语言:javascript
复制
x = np.array([1,2])
y = np.array([2,1])

这样的话

代码语言:javascript
复制
(x>y) == np.array([0,1])

if np.array([0,1])语句的结果应该是什么?这是对还是错?numpy告诉你这是模棱两可的。使用

代码语言:javascript
复制
(x>y).all()

代码语言:javascript
复制
(x>y).any()

是明确的,因此numpy为您提供了解决方案-无论是任何单元格对满足条件,还是所有单元格对都满足条件-两者都是明确的真值。你必须自己定义,你所说的向量x大于向量y是什么意思。

在所有xy对上运行的numpy解决方案,使得x[i]>y[j]使用网格网格来生成所有对:

代码语言:javascript
复制
>>> import numpy as np
>>> x=np.array(range(10))
>>> y=np.array(range(10))
>>> xv,yv=np.meshgrid(x,y)
>>> xv[xv>yv]
array([1, 2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8,
       9, 4, 5, 6, 7, 8, 9, 5, 6, 7, 8, 9, 6, 7, 8, 9, 7, 8, 9, 8, 9, 9])
>>> yv[xv>yv]
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
       2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 8])

xvyv发送到fun,或者在函数中创建网格,具体取决于哪个更有意义。这将生成所有成对的xi,yj,使得xi>yj。如果您想要实际的索引,只需返回xv>yv,其中每个单元格ij对应x[i]y[j]。在您的案例中:

代码语言:javascript
复制
def fun(x, y):
    xv,yv=np.meshgrid(x,y)
    return xv>yv

将返回一个矩阵,如果为x[i]>y[j],则fun(x,y)[i][j]为True,否则为False。另一个选择

代码语言:javascript
复制
return  np.where(xv>yv)

将返回由索引对的两个数组组成的元组,以便

代码语言:javascript
复制
for i,j in fun(x,y):

也将保证x[i]>y[j]

票数 1
EN

Stack Overflow用户

发布于 2018-12-04 02:02:13

代码语言:javascript
复制
In [253]: x = np.random.randint(0,10,5)
In [254]: y = np.random.randint(0,10,5)
In [255]: x
Out[255]: array([3, 2, 2, 2, 5])
In [256]: y
Out[256]: array([2, 6, 7, 6, 5])
In [257]: x>y
Out[257]: array([ True, False, False, False, False])
In [258]: np.where(x>y,0,1)
Out[258]: array([0, 1, 1, 1, 1])

要对这两个一维数组进行笛卡尔比较,请重塑一个数组,以便它可以使用broadcasting

代码语言:javascript
复制
In [259]: x[:,None]>y
Out[259]: 
array([[ True, False, False, False, False],
       [False, False, False, False, False],
       [False, False, False, False, False],
       [False, False, False, False, False],
       [ True, False, False, False, False]])
In [260]: np.where(x[:,None]>y,0,1)
Out[260]: 
array([[0, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [0, 1, 1, 1, 1]])

使用if的函数只适用于标量输入。如果给定了数组,a>b将生成一个不能在if语句中使用的布尔数组。您的迭代之所以有效,是因为它传递标量值。对于一些复杂的函数,这是您所能做的最好的事情(np.vectorize可以使迭代更简单,但不会更快)。

我的答案是查看数组比较,并从中得出答案。在本例中,3个参数where很好地将布尔数组映射到所需的I/0。还有其他方法也可以进行这种映射。

您的双循环需要一个额外的编码层,即广播的None

票数 1
EN

Stack Overflow用户

发布于 2018-12-04 23:48:54

对于更复杂的示例,或者如果您正在处理的数组有点大,或者如果您可以写入已经预先分配的数组,则可以考虑使用Numba

示例

代码语言:javascript
复制
import numba as nb
import numpy as np

@nb.njit()
def fun(x, y):
  if x > y:
    return 0
  else:
    return 1

@nb.njit(parallel=False)
#@nb.njit(parallel=True)
def loop(x,y):
  result=np.empty((x.shape[0],y.shape[0]),dtype=np.int32)
  for i in nb.prange(x.shape[0]):
    for j in range(y.shape[0]):
      result[i,j] = fun(x[i], y[j])
  return result

@nb.njit(parallel=False)
def loop_preallocated(x,y,result):
  for i in nb.prange(x.shape[0]):
    for j in range(y.shape[0]):
      result[i,j] = fun(x[i], y[j])
  return result

计时

代码语言:javascript
复制
x = np.array(range(1000))
y = np.array(range(1000))

#Compilation overhead of the first call is neglected

res=np.where(x[:,None]>y,0,1) -> 2.46ms
loop(single_threaded)         -> 1.23ms
loop(parallel)                -> 1.0ms
loop(single_threaded)*        -> 0.27ms
loop(parallel)*               -> 0.058ms

*可能受缓存的影响。在你自己的例子上进行测试。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53594769

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档