【问题标题】:How to efficiently apply functions to values in an array based on condition?如何根据条件有效地将函数应用于数组中的值?
【发布时间】:2017-09-23 19:57:35
【问题描述】:

我有一个这样的数组arorg

import numpy as np
arorg = np.array([[-1., 2., -4.], [0.5, -1.5, 3]])

还有另一个数组values,如下所示:

values = np.array([1., 0., 2.])

values 的条目数与 arorg 的列数相同。

现在我想将函数应用于条目或arorg,具体取决于它们是正数还是负数:

def neg_fun(val1, val2):
    return val1 / (val1 + abs(val2))

def pos_fun(val1, val2):
    return 1. / ((val1 / val2) + 1.)

因此,val2arorgval1 中的(绝对)值——这是棘手的部分——来自values;如果我将pos_funneg_fun 应用于arorg 中的i 列,val1 应该是values[i]

我目前实现如下:

ar = arorg.copy()

for (x, y) in zip(*np.where(ar > 0)):
    ar.itemset((x, y), pos_fun(values[y], ar.item(x, y)))

for (x, y) in zip(*np.where(ar < 0)):
    ar.itemset((x, y), neg_fun(values[y], ar.item(x, y)))

这给了我想要的输出:

array([[ 0.5       ,  1.        ,  0.33333333],
       [ 0.33333333,  0.        ,  0.6       ]])

由于我必须经常进行这些计算,我想知道是否有更有效的方法来执行此操作。像

np.where(arorg > 0, pos_fun(xxxx), arorg)

会很棒,但我不知道如何正确传递参数(xxx)。有什么建议吗?

【问题讨论】:

  • 对于返回值的[0,0]项,答案应该是inf吗? arorg[0,0] 是负数,所以我们应用neg_fun,它的分母是0val1 / (val1 + val2) = 1. / (1. - 1.)
  • @James: arorg[0, 0]-1,所以我们确实申请了neg_funvalues[0]1.。然后我们会得到:1. / (1. + abs(-1)) = 0.5。你在哪里看到inf
  • 同样对于[0,3]项,结果应该是-1 (2/(-4+2))吗?
  • 您的函数中没有包含abs
  • 在你的 func def 中,没有 abs()

标签: python arrays performance numpy vectorization


【解决方案1】:

正如问题中所暗示的,这里使用np.where

首先,我们使用函数实现的直接翻译来生成正负两种情况的值/数组。然后,使用正值掩码,我们将使用np.where 在这两个数组之间进行选择。

因此,实现看起来应该是这样的 -

# Get positive and negative values for all elements
val1 = values
val2 = arorg
neg_vals = val1 / (val1 + np.abs(val2))
pos_vals = 1. / ((val1 / val2) + 1.)

# Get a positive mask and choose between positive and negative values 
pos_mask = arorg > 0
out = np.where(pos_mask, pos_vals, neg_vals)

【讨论】:

    【解决方案2】:

    你不需要对数组的压缩元素应用函数,你可以通过简单的数组操作和切片来完成同样的事情。

    首先,得到正负计算,保存为数组。然后创建一个零返回数组(就像默认值一样),并使用 posneg 的布尔切片填充它:

    import numpy as np
    arorg = np.array([[-1., 2., -4.], [0.5, -1.5, 3]])
    values = np.array([1., 0., 2.])
    
    pos = 1. / ((values / arorg) + 1)
    neg = values / (values + np.abs(arorg))
    
    ret = np.zeros_like(arorg)
    ret[arorg>0] = pos[arorg>0]
    ret[arorg<=0] = neg[arorg<=0]
    
    ret
    # returns:
    array([[ 0.5       ,  1.        ,  0.33333333],
           [ 0.33333333,  0.        ,  0.6       ]])
    

    【讨论】:

      【解决方案3】:
      import numpy as np
      arorg = np.array([[-1., 2., -4.], [0.5, -1.5, 3]])
      values = np.array([1., 0., 2.])
      p = 1.0/(values/arorg+1)
      n = values/(values+abs(arorg))
      #using np.place to extract negative values and put them to p
      np.place(p,arorg<0,n[arorg<0])
      print(p)
      [[ 0.5         1.          0.33333333]
       [ 0.33333333  0.          0.6       ]]
      

      【讨论】:

      • 工作正常,谢谢(赞成)!只是一件小事:a 没有定义,应该是arorg
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-04
      • 2021-04-20
      • 1970-01-01
      • 2017-03-07
      • 2017-01-11
      • 1970-01-01
      相关资源
      最近更新 更多