将函数向量应用于参数向量

时间:2016-09-16 16:01:05

标签: python numpy vectorization

我想要接受一系列函数funclist,并返回一个新函数,该函数接收参数列表arglist,并应用ifunclisti的{​​{1}}元素中运行,将结果返回到列表中:

arglist

这不是针对def myfunc(funclist): return lambda arglist: [ funclist[i](elt) for i, elt in enumerate(arglist) ] 中的独立函数与funclist中的独立参数的并行/矢量化应用进行优化的。 python或numpy(或其他)中是否有内置函数会返回上面argvec的更优化版本?它在精神上与lambdamap相似(但显然不一样),到目前为止我还没有找到任何东西。

1 个答案:

答案 0 :(得分:3)

numpy术语中,真正的矢量化意味着在编译的代码中执行迭代的东西。通常,这需要使用适用于整个数组的numpy函数,执行添加和索引等操作。

np.vectorize是一种迭代多个数组的方法,并在不处理数组的函数中使用它们的元素。它在编译代码中没有多大作用,因此不会提高速度。作为将numpy广播规则应用于您自己的标量函数的一种方式,它是最有价值的。

map是列表推导的变体,速度基本相同。列表理解具有更强的表达能力,可以使用多个列表。

@Tore's压缩理解是这项任务的明确表达

[f(args) for f, args in zip(funclist, arglist)]

map可以使用多个输入列表:

In [415]: arglist=[np.arange(3),np.arange(1,4)]
In [416]: fnlist=[np.sum, np.prod]
In [417]: [f(a) for f,a in zip(fnlist, arglist)]
Out[417]: [3, 6]
In [418]: list(map(lambda f,a: f(a), fnlist, arglist))
Out[418]: [3, 6]

你的版本有点啰嗦,但功能相同。

In [423]: def myfunc(funclist):
     ...:     return lambda arglist: [ funclist[i](elt) for i, elt in enumerate(arglist) ]

In [424]: myfunc(fnlist)
Out[424]: <function __main__.myfunc.<locals>.<lambda>>
In [425]: myfunc(fnlist)(arglist)
Out[425]: [3, 6]

它的优点是可以生成一个可以应用于不同arglists的函数:

In [426]: flist=myfunc(fnlist)
In [427]: flist(arglist)
Out[427]: [3, 6]
In [428]: flist(arglist[::-1])
Out[428]: [6, 0]

我会写myfunc更像是:

def altfun(funclist):
   def foo(arglist):
       return [f(a) for f,a in zip(funclist, arglist)]
   return foo

但差异只是风格上的。

=====

zip v enumerate的时间测试:

In [154]: funclist=[sum]*N
In [155]: arglist=[list(range(N))]*N
In [156]: sum([funclist[i](args) for i,args in enumerate(arglist)])
Out[156]: 499500000
In [157]: sum([f(args) for f,args in zip(funclist, arglist)])
Out[157]: 499500000

In [158]: timeit [funclist[i](args) for i,args in enumerate(arglist)]
10 loops, best of 3: 43.5 ms per loop

In [159]: timeit [f(args) for f,args in zip(funclist, arglist)]
10 loops, best of 3: 43.1 ms per loop

基本相同。但map快2倍

In [161]: timeit list(map(lambda f,a: f(a), funclist, arglist))
10 loops, best of 3: 23.1 ms per loop

将迭代打包在可调用中也更快

In [165]: timeit altfun(funclist)(arglist)
10 loops, best of 3: 23 ms per loop
In [179]: timeit myfunc(funclist)(arglist)
10 loops, best of 3: 22.6 ms per loop