【问题标题】:Can I vectorise a list comprehension using np.vectorize()?我可以使用 np.vectorize() 对列表理解进行矢量化吗?
【发布时间】:2020-02-13 05:40:31
【问题描述】:

我是 Python 的新手,从 NumPy 开始。
我尝试执行以下操作:

a = np.arange(1, 20)  
f = np.vectorize([x/(x+1) for x in a])  
f(a)  
TypeError: 'list' object is not callable <-- got this error

所以我想知道是否可以矢量化列表理解 另外“对象不可调用”是什么意思?备查 提前致谢

【问题讨论】:

  • 你的预期输出是什么
  • 当你f(a) 时你期望什么?

标签: python python-3.x numpy vectorization


【解决方案1】:

不要浪费时间尝试使用np.vectorize,尤其是当您可以进行真正的 numpy 矢量化时。不要被名字所迷惑。这不是快速数值计算的捷径。

In [442]: a = np.arange(1,5)

你的列表理解:

In [443]: [x/(x+1) for x in a]
Out[443]: [0.5, 0.6666666666666666, 0.75, 0.8]

可以通过简单的 numpy 数组操作来完成:

In [444]: a/(a+1)
Out[444]: array([0.5, 0.66666667, 0.75, 0.8])

但是让我们假设我们有一个只适用于标量输入的函数:

In [445]: f = np.vectorize(lambda x: x/(x+1), otypes=[float])
In [446]: f(a)
Out[446]: array([0.5, 0.66666667, 0.75 , 0.8])

它可以工作,但它比 [444] 慢得多,并且不比 [443] 快。

【讨论】:

    【解决方案2】:

    所以我想知道是否可以将列表理解向量化。

    np.vectorize 会将函数转换为接受数组作为输入的函数。然后,您可以使用它来代替列表推导。

    但从性能的角度来看,它并没有“矢量化”操作。事实上,它通常速度较慢,用于测试或语法调整。

    “对象不可调用”是什么意思?

    在 Python 中,“可调用”是可以“作为函数”使用的对象。当然,函数是可调用的。您可以将__call__ 方法添加到其他对象。

    下面是具有__call__ 方法的类示例。

    In [33]: class myclass():
        ...:     def __init__(self):
        ...:         pass
        ...:     def __call__(self, x):
        ...:         return x**2
        ...: 
        ...: 
    
    In [34]: A = myclass()
    
    In [35]: A(10)
    Out[35]: 100
    

    [x/(x+1) for x in a]是一个表达式,它返回一个值,不能被调用。 np.vectorize 的参数必须是可调用的。

    这里的其他人建议使用np.vectorize(lambda x: x/(1+x))

    def f(x):
        return x/(1+x)
    
    f_vec = np.vectorize(f)
    

    第一个是“lambda 函数”,第二个是常规函数。两者都是可调用的。

    对于你展示的情况,你确实可以做到

    y = x/(1+x)
    

    这将使用 NumPy 操作。由于 x 是一个数组,这被认为是一种向量化形式(计算将在优化和向量化的 C++ 代码中进行)。

    对于更复杂的计算,请查找 Cython、numexpr 或 Numba。

    【讨论】:

    • 谢谢!您的可调用解释确实清除了它,我现在可以更好地处理此类错误
    【解决方案3】:

    我认为您可能对列表理解和 np.vectorize 的作用有些困惑。 np.vectorize 以一种可以将其应用于整个列表的方式更改函数。你应该使用的是 -

    def foo(x):
        return(x/(x+1))
    
    f = np.vectorize(foo)
    a = np.arange(1, 20) 
    
    f(a)
    

    使用[x/(x+1) for x in a] 将获得与 f(a) 相同的结果,只是执行时间会有所不同。

    您收到“list not callable”错误的原因是因为 f 是一个列表而不是一个函数,并且您试图将一个参数 (a) 传递给一个列表。

    【讨论】:

      猜你喜欢
      • 2013-06-09
      • 1970-01-01
      • 2020-01-15
      • 2014-08-06
      • 1970-01-01
      • 2015-02-24
      • 2019-01-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多