import numpy as np
def f(x):
return x * x + 3 * x - 2 if x > 0 else x * 5 + 8
f = np.vectorize(f) # or use a different name if you want to keep the original f
result_array = f(A) # if A is your Numpy array
from llvmlite import binding
# set before import
binding.set_option('SVML', '-vector-library=SVML')
import numba as nb
@nb.vectorize(target="cpu")
def nb_vexp_svml(x):
return np.exp(x)
import perfplot
perfplot.show(
setup=lambda n: np.random.rand(n,n)[::2,::2],
n_range=[2**k for k in range(0,12)],
kernels=[
f,
vf,
nb_vf
],
logx=True,
logy=True,
xlabel='len(x)'
)
B. exp的比较:
import perfplot
import numexpr as ne # using ne is the easiest way to set vml_num_threads
ne.set_vml_num_threads(1)
perfplot.show(
setup=lambda n: np.random.rand(n,n)[::2,::2],
n_range=[2**k for k in range(0,12)],
kernels=[
nb_vexp,
np.exp,
np_copy_exp,
],
logx=True,
logy=True,
xlabel='len(x)',
)
import numpy, time
def A(e):
return e * e
def timeit():
y = numpy.arange(1000000)
now = time.time()
numpy.array([A(x) for x in y.reshape(-1)]).reshape(y.shape)
print(time.time() - now)
now = time.time()
numpy.fromiter((A(x) for x in y.reshape(-1)), y.dtype).reshape(y.shape)
print(time.time() - now)
now = time.time()
numpy.square(y)
print(time.time() - now)
输出
>>> timeit()
1.162431240081787 # list comprehension and then building numpy array
1.0775556564331055 # from numpy.fromiter
0.002948284149169922 # using inbuilt function
在这里你可以清楚地看到numpy.fromiter用户广场功能,使用任何你的选择。如果你的函数依赖于i, j,这是数组的索引,那么就像for ind in range(arr.size)这样的数组的大小,使用numpy.unravel_index根据你的一维索引和数组numpy的形状来获得i, j, ..。unravel_index 这个答案的灵感来自于我对另一个问题here的回答
6条答案
按热度按时间x0fgdtte1#
你可以只vectorize这个函数,然后在每次需要它的时候直接将它应用到Numpy数组中:
在向量化时直接指定显式输出类型可能更好:
up9lanfz2#
类似的问题是:Mapping a NumPy array in place .如果你能为f()找到一个ufunc,那么你应该使用out参数。
odopli943#
如果你正在处理数字和
f(A(i,j)) = f(A(j,i))
,你可以使用scipy.spatial.distance.cdist将f定义为A(i)
和A(j)
之间的距离。hyrbngr74#
我想我找到了一个更好的解决办法。将函数改为python通用函数的想法(参见documentation),它可以在后台执行并行计算。
可以用C编写自己的定制
ufunc
,这肯定更有效,或者通过调用np.frompyfunc
,这是内置的工厂方法。经过测试,这比np.vectorize
更有效:我也测试了更大的样本,改进是成比例的。其他方法的性能比较见this post
643ylb085#
当2d数组(或nd-array)是C-或F-连续的,那么将函数Map到2d数组上的任务实际上与将函数Map到1d数组上的任务相同-我们只需要这样看待它,例如。通过
np.ravel(A,'K')
。一维阵列的可能解决方案已经讨论过,例如here。
然而,当2d数组的内存不连续时,情况就有点复杂了,因为如果轴以错误的顺序处理,人们希望避免可能的缓存未命中。
Numpy已经有了一台机器,可以以最佳顺序加工轴。使用这种机器的一种可能性是
np.vectorize
。然而,numpy在np.vectorize
上的文档指出,它“主要是为了方便而提供的,而不是为了性能”-一个慢的python函数仍然是一个慢的python函数,具有整个相关的开销!另一个问题是它巨大的内存消耗-例如,参见SO-post。当一个人想要有一个C函数的性能,但使用numpy的机器,一个很好的解决方案是使用numba创建ufuncs,例如:
它很容易击败
np.vectorize
,而且当相同的功能将被执行为numpy数组乘法/加法时,即。时间测量代码见本答复的附录:
Numba的版本(绿色)比python函数(即
np.vectorize
),这并不奇怪。但它也比numpy-function快10倍左右,因为numbas版本不需要中间数组,因此更有效地使用缓存。虽然numba的ufunc方法是可用性和性能之间的一个很好的折衷,但它仍然不是我们能做的最好的。然而,对于任何任务,都没有最佳的银或方法--人们必须了解限制是什么以及如何减轻限制。
例如,对于超越函数(例如,
exp
,sin
,cos
)numba与numpy的np.exp
相比没有任何优势(没有创建临时数组-这是加速的主要来源)。然而,我的Anaconda安装使用Intel的VML来处理大于8192的向量-如果内存不连续,它就不能这样做。因此,最好将元素复制到连续内存中,以便能够使用英特尔的VML:为了比较的公平性,我关闭了VML的并行化(参见附录中的代码):
可以看到,一旦VML开始工作,复制的开销就得到了补偿。然而,一旦数据对于L3缓存来说变得太大,那么优势就很小,因为任务再次成为内存带宽限制。
另一方面,numba也可以使用Intel的SVML,如this post中所解释的:
使用具有并行化的VML可以得到:
numba的版本开销更小,但对于某些大小,VML甚至优于SVML,尽管有额外的复制开销-这并不奇怪,因为numba的ufuncs不是并行的。
列表:
A.多项式函数的比较:
B.
exp
的比较:bzzcjhmw6#
上面的答案都比较好,但是如果你需要使用自定义函数进行Map,并且你有
numpy.ndarray
,你需要保持数组的形状。我只比较了两个,但它将保留
ndarray
的形状。我使用了具有100万个条目的数组进行比较。这里我使用平方函数。我将介绍n维数组的一般情况。对于二维,只需将iter
用于2D。输出
在这里你可以清楚地看到
numpy.fromiter
用户广场功能,使用任何你的选择。如果你的函数依赖于i, j
,这是数组的索引,那么就像for ind in range(arr.size)
这样的数组的大小,使用numpy.unravel_index
根据你的一维索引和数组numpy的形状来获得i, j, ..
。unravel_index这个答案的灵感来自于我对另一个问题here的回答