Python 在不并行化的情况下提高函数的性能

Python 在不并行化的情况下提高函数的性能,python,arrays,performance,numpy,Python,Arrays,Performance,Numpy,几周前,我发布了一个问题(),得到了非常好的答案。这个问题与那个问题相关,因为它利用了用户建议的性能改进 我需要改进一个函数的性能,这个函数需要计算三个因子,然后对它们应用指数 这是我的代码的MWE: import numpy as np import timeit def random_data(N): # Generate some random data. return np.random.uniform(0., 10., N) # Data lists. array1

几周前,我发布了一个问题(),得到了非常好的答案。这个问题与那个问题相关,因为它利用了用户建议的性能改进

我需要改进一个函数的性能,这个函数需要计算三个因子,然后对它们应用指数

这是我的代码的
MWE

import numpy as np
import timeit

def random_data(N):
    # Generate some random data.
    return np.random.uniform(0., 10., N)

# Data lists.
array1 = np.array([random_data(4) for _ in range(1000)])
array2 = np.array([random_data(3) for _ in range(2000)])

# Function.
def func():
    # Empty list that holds all values obtained in for loop.    
    lst = []
    for elem in array1:
        # Avoid numeric errors if one of these values is 0.            
        e_1, e_2 = max(elem[0], 1e-10), max(elem[1], 1e-10)
        # Obtain three parameters.
        A = 1./(e_1*e_2)
        B = -0.5*((elem[2]-array2[:,0])/e_1)**2
        C = -0.5*((elem[3]-array2[:,1])/e_2)**2
        # Apply exponential.
        value = A*np.exp(B+C)
        # Store value in list.
        lst.append(value)

    return lst

# time function.
func_time = timeit.timeit(func, number=100)
print func_time

有没有可能在不必重新进行并行化的情况下加速
func
。我的方法是在numpy数组中尽可能多地进行数学运算

优化:

  • 在numpy内计算
    A
    s
  • 通过将
    B
    C
    拆分为因子,重新计算因子,其中一些因子可以在numpy内计算
代码:

结果:

True
0.759s --> 0.485s
True
0.780s --> 0.558s

在这一点上,我被卡住了。我在完全没有python for循环的情况下成功地做到了这一点,但它比上面的版本慢,原因我还不明白:

def optfunc():
    x = array1
    y = array2

    x0 = x[:, 0]
    x1 = x[:, 1]
    x2 = x[:, 2]
    x3 = x[:, 3]

    y0 = y[:, 0]
    y1 = y[:, 1]

    A = 1./(x0 * x1)
    Bfactors = -0.5 * (1 / x0**2)
    Cfactors = -0.5 * (1 / x1**2)

    B = (np.transpose([x2]) - y0)**2 * np.transpose([Bfactors])
    C = (np.transpose([x3]) - y1)**2 * np.transpose([Cfactors])

    return np.transpose([A]) * np.exp(B + C)
结果:

True
0.759s --> 0.485s
True
0.780s --> 0.558s

但是请注意,后者为您提供一个
np.array
,而前者仅为您提供一个Python列表。。。这可能是造成差异的原因,但我不确定。

以下是我目前掌握的情况。我的方法是在numpy数组中尽可能多地进行数学运算

优化:

  • 在numpy内计算
    A
    s
  • 通过将
    B
    C
    拆分为因子,重新计算因子,其中一些因子可以在numpy内计算
代码:

结果:

True
0.759s --> 0.485s
True
0.780s --> 0.558s

在这一点上,我被卡住了。我在完全没有python for循环的情况下成功地做到了这一点,但它比上面的版本慢,原因我还不明白:

def optfunc():
    x = array1
    y = array2

    x0 = x[:, 0]
    x1 = x[:, 1]
    x2 = x[:, 2]
    x3 = x[:, 3]

    y0 = y[:, 0]
    y1 = y[:, 1]

    A = 1./(x0 * x1)
    Bfactors = -0.5 * (1 / x0**2)
    Cfactors = -0.5 * (1 / x1**2)

    B = (np.transpose([x2]) - y0)**2 * np.transpose([Bfactors])
    C = (np.transpose([x3]) - y1)**2 * np.transpose([Cfactors])

    return np.transpose([A]) * np.exp(B + C)
结果:

True
0.759s --> 0.485s
True
0.780s --> 0.558s

但是请注意,后者为您提供一个
np.array
,而前者仅为您提供一个Python列表。。。这可能是造成差异的原因,但我不确定。

您在第一次迭代后从函数返回,这是有意的吗?啊,没有对不起的错误缩进。我现在就修。谢谢你的提醒!但是像这样,您只使用上一次迭代的A、B、C。您可能还希望在函数内部移动
lst=[]
。像这样,您继续添加到同一个列表中,每次执行timeit时,列表都会不断增加。本文应该给您一些好主意:您在第一次迭代后从函数返回,这是有意的吗?啊,抱歉,没有错误的缩进。我现在就修。谢谢你的提醒!但是像这样,您只使用上一次迭代的A、B、C。您可能还希望在函数内部移动
lst=[]
。就像这样,你不断地添加到同一个列表中,每次你做timeit时,这个列表都会不断增加。这篇文章应该会给你一些好主意:非常感谢@Claudiu,我已经到了一个地步,每一点优化都很重要,所以你的回答肯定会帮助我。我已经从你的答案中删除了两个没有被使用的因素。干杯。小评论:在我的问题中,我用
max(elem[0],1e-10)
(与
e_2
相同)定义了
e_1
,以避免其中一个为零时出现数字错误。在这种情况下,你的答案会发生什么?@Gabriel:注意我的输出打印了
np.allclose(optfunc(),func())
,并且得到了
True
——这意味着我们的两个答案都在一定的公差范围内。如果其中一个是零,我不确定你期望得到什么答案,因为你被零除,然后得到无穷大。。但是无论如何,如果你想要完全相同的行为,只要做
e0=array1[:,0];e0[e0<1e-10]=1e-10
将下面的所有元素设置为
1e-10
非常感谢@Claudiu,我已经到了每一点优化都很重要的地步,所以你的答案肯定会对我有所帮助。我已经从你的答案中删除了两个没有被使用的因素。干杯。小评论:在我的问题中,我用
max(elem[0],1e-10)
(与
e_2
相同)定义了
e_1
,以避免其中一个为零时出现数字错误。在这种情况下,你的答案会发生什么?@Gabriel:注意我的输出打印了
np.allclose(optfunc(),func())
,并且得到了
True
——这意味着我们的两个答案都在一定的公差范围内。如果其中一个是零,我不确定你期望得到什么答案,因为你被零除,然后得到无穷大。。但是无论如何,如果你想要完全相同的行为,只要做
e0=array1[:,0];e0[e0<1e-10]=1e-10
1e-10
以下所有元素设置为
1e-10