【问题标题】:Vectorised of loop with condition code using numpy使用 numpy 对带有条件代码的循环进行向量化
【发布时间】:2020-07-04 22:33:16
【问题描述】:

我正在尝试将简单代码转换为矢量化器。我是这个概念的新手。

我尝试过使用np.vectorize 选项,但它会引发错误:

你能帮我解决这个问题吗?有没有其他更好的方法来矢量化它?


代码:

   def test(s,m):
      mean_matrix=s
      m2=s/m // forming an array
      result=[]
      for x in m2:
         return x/5



  s=np.random.random(50)
  m=np.random.random(100)
  temp=np.vectorize(test,otypes=[np.float],cache=False)
  out = temp(s,m)

【问题讨论】:

  • numpy.vectorize 的原理是能够对输入数组的连续元组应用函数。例如,如果您有一个仅将标量作为输入的函数,您将能够将其应用于向量。在您的情况下,您不想使用此函数,因为 test 函数已经是一个向量化函数,因为它接受向量。
  • 如果你有一个函数 test 使得 result[i]=test(s[i],m[i]) ,那么使用 numpy.vectorize 会是一个好主意。这不是这里的配置,因为 test 需要整个 s 向量来计算平均值。
  • np.vectorize 不会执行您所寻求的速度增强“矢量化”。您对otypes 的使用告诉我您阅读了它的文档,但显然您错过了性能免责声明。
  • np.vectorize 将标量参数传递给您的函数,因此当您尝试s[0] 时会出现抱怨。 otypes 确定返回 dtype,但对输入不做任何事情。在开发这样的代码时,最好检查输入参数的类型/形状/dtype。

标签: python numpy loops conditional-statements vectorization


【解决方案1】:

首先将您的代码分成循环中使用的部分(可以矢量化)和其余部分(已经矢量化):

def kernel(s, x):
    i = 0
    initial_value = s[0].copy()
    while initial_value < x:
        i = i+1
        initial_value += s[i]
    return i

def test_split(s, m):
    mean_matrix = s.mean() # 5 usec
    product_m2 = mean_matrix * m # forming an array, 2 usec
    return [kernel(s, x) for x in product_m2] # 167 usec

test_splittest 做同样的事情,只是被重构了。我已经对每一行进行了注释,说明在那里花费了多少时间,以表明加快循环速度会有所作为。

如果你使用np.vectorize(),它看起来像这样:

def test_vectorize(s, m):
    mean_matrix = s.mean() # 5 usec
    product_m2 = mean_matrix * m # forming an array, 2 usec
    kernel_vec = np.vectorize(lambda x: kernel(s, x)) # 2 usec
    return kernel_vec(product_m2) # 194 usec

这更慢!那是因为np.vectorize() 不会让事情变得更快,它只会改变美学。它仍然在内部使用 Python 循环。最好忘记它的存在。

所以我们需要一种不同的方法,为此我们需要考虑kernel 做了什么。在我看来,它所做的是找到s 的最长初始子序列,其总和小于xs.cumsum() 将为我们提供我们需要的运行总数,但是我们如何在product_m2 中搜索小于每个x 的最大长度?我们不能使用循环,否则它会再次变慢。但是我们可以使用np.searchsorted()。这里是:

def test_fast(s, m):
     mean_matrix = s.mean() # 5 usec
     product_m2 = mean_matrix * m # forming an array, 2 usec
     s_sum = s.cumsum() # 1 usec
     return s_sum.searchsorted(product_m2) # 2 usec

这样我们就有了 14 倍的加速。

【讨论】:

  • 感谢约翰,您的回答。我明白你的意思。但您的代码只返回一个值。但根据我的初始代码,它应该返回 m 长度向量,其中 product_m2 中的每个值都应该比较 s[0] 的初始值,然后找到总和小于 product_m2 的 s 的最长初始子序列,然后返回循环的最大值.这个过程对所有 M 值重复,所以我们可以得到 m 向量。请您指导。
  • @Chanakya:你试过运行我的代码吗?如果我使用您的示例 s(长度 50)和 m(长度 100)并运行 test_fast(s, m),它将返回一个包含 100 个元素的数组,这些元素的值与原始 test(s, m) 返回的 100 个元素的列表具有相同的值.
  • 兹维克感谢您的回复。我尝试了您的代码并将其称为 ` m=np.random.random(100) ` s = np.random.random(10) test_fast(s, m) ` 但它只返回一个值
  • 输出是什么?它应该输出一个数组。它在我的电脑上。显示你得到的输出,并告诉我们你正在使用哪个版本的 NumPy。
  • 谢谢,约翰。它正在工作,实际上它正在发挥工作价值......非常感谢您的帮助。请您告诉我学习vectorizer的有效方法。
猜你喜欢
  • 1970-01-01
  • 2020-10-20
  • 1970-01-01
  • 1970-01-01
  • 2018-08-26
  • 2017-04-29
  • 2017-12-09
  • 1970-01-01
  • 2020-12-08
相关资源
最近更新 更多