【问题标题】:How can I improve the performance of the below python code如何提高以下 python 代码的性能
【发布时间】:2016-06-20 04:41:03
【问题描述】:

我编写了如下所示的这段代码。我遇到了严重的性能问题。尤其是我循环 5000 万次的循环(对于 z in range(total):) 似乎非常慢。我可以修改它以提高效率吗? - 也许修改它如何在 r1,r2 中存储最后 10 个值的总和?

import numpy as np
import math
import scipy.stats as sp

# Define sample size 
sample=4999999
cutoff=int((sample+1)/100)
# Define days for x-day VaR
xdays=10

# Calculate the whole sample size and extended total sample size
size=sample*xdays+xdays-1
total=size+xdays
cutoff_o=int((size+1)/100)


# Sample values for kurtosis
#kurt=[0.0000001,1.0,2.0,3.0,4.0,5.0,6.0,10.0]

kurt=[6.0]

# Number of repetitions
rep=2

# Define correlation coefficient
rho=0.5

# Loop for different iterations
for x in range(rep):
    uni=sp.uniform.rvs(size=total)

# Loop for different values of kurtosis
    for y in kurt:
        df=(6.0/y)+4.0

        # Initialize arrays
        t_corr=np.empty(total)
        n_corr=np.empty(total)
        t_corr_2=np.empty(total)

        r1=np.empty(sample)
        r2=np.empty(size)

        r3=np.empty(sample)
        r4=np.empty(size)

        # Define t dist from uniform
        t_dist=sp.t.ppf(uni,df)
        n_dist=sp.norm.ppf(uni)

        # Loop to generate autocorrelated distributions
        for z in range(total):
            if z==0:
                t_corr[z]=t_dist[z]
                n_corr[z]=n_dist[z]
                t_corr_2[z]=sp.t.ppf(sp.norm.cdf(n_corr[z]),df)
            else:
                t_corr[z]=rho*t_dist[z-1] + math.sqrt((1-rho**2))*t_dist[z]
                n_corr[z]=rho*n_dist[z-1] + math.sqrt((1-rho**2))*n_dist[z]
                t_corr_2[z]=sp.t.ppf(sp.norm.cdf(n_corr[z]),df)
            if z>xdays-1:
                z_x=int(z/xdays)-1
                if (z%xdays)==0 and z_x<sample:
                    r1[z_x]= sum(t_corr[z-10:z])
                    r3[z_x]= sum(t_corr_2[z-10:z])

                r2[z-xdays]= sum(t_corr[z-10:z])
                r4[z-xdays]= sum(t_corr_2[z-10:z])

        print (np.partition(r1, cutoff-1)[cutoff-1], np.partition(r3, cutoff-1)[cutoff-1], np.partition(r2, cutoff_o-1)[cutoff_o-1], np.partition(r4, cutoff_o-1)[cutoff_o-1])
    print ()

【问题讨论】:

  • 学习使用分析器。我可以在这里猜到一些改进,但我不想保证它们甚至会提高速度。例如。 t_corrn_corrt_corr_2 的元素似乎不超过十个,t_distn_dist 的单个元素,那么为什么要为它们创建大数组呢?
  • 如果您正在寻求代码中的性能改进,您应该在CodeReview 询问

标签: python performance loops python-3.x coding-efficiency


【解决方案1】:

一些建议:

不必要的 ifs

首先,您可以从循环中删除 if 语句。当您(程序员)知道 z 在第一个循环中等于 0 时,检查 z == 0 数百万次似乎有点不必要。 if z&gt;xdays-1 也是如此:

if z==0:
    t_corr[z]=t_dist[z]
    n_corr[z]=n_dist[z]
    t_corr_2[z]=sp.t.ppf(sp.norm.cdf(n_corr[z]),df)

for z in range(1, xdays - 1):
    t_corr[z]=rho*t_dist[z-1] + math.sqrt((1-rho**2))*t_dist[z]
    n_corr[z]=rho*n_dist[z-1] + math.sqrt((1-rho**2))*n_dist[z]
    t_corr_2[z]=sp.t.ppf(sp.norm.cdf(n_corr[z]),df)

for z in range(xdays - 1, total)
    t_corr[z]=rho*t_dist[z-1] + math.sqrt((1-rho**2))*t_dist[z]
    n_corr[z]=rho*n_dist[z-1] + math.sqrt((1-rho**2))*n_dist[z]
    t_corr_2[z]=sp.t.ppf(sp.norm.cdf(n_corr[z]),df)
    z_x=int(z/xdays)-1
    if (z%xdays)==0 and z_x<sample:
        r1[z_x]= sum(t_corr[z-10:z])
        r3[z_x]= sum(t_corr_2[z-10:z])    
    r2[z-xdays]= sum(t_corr[z-10:z])
    r4[z-xdays]= sum(t_corr_2[z-10:z])

请仔细检查;我只是把它扔了:)

编译你的代码!

一个便宜的/黑客修复,实际上可以提供一些严重的好处!您可以尝试将您的 python 代码编译成二进制文件,例如使用 Cython。我实际上用一个人为但与你的例子相似的例子对此进行了测试,我希望它能为你提供足够的信息来开始。假设我有以下 python 脚本:

import math

for j in range(1000):
    for i in range(1000):
        a = math.sqrt(i) * math.sqrt(j)

在我的 Ubuntu VM 上使用 python3 fast.py 运行它需要持续 0.4 秒的实时时间。运行以下命令:

$ cython3 --embed -o fast.c fast.py
$ gcc -I /usr/include/python3.4m/ -o fast fast.c -lpython3.4m

从我的 python 代码生成一个.c 文件,并从中自动为我编译二进制文件fast。现在运行可执行文件给了我 0.14 秒的平均实时时间 - 一个巨大的改进!

更少的列表切片(编辑 - 没有帮助,这是 NumPy 切片而不是列表切片!)

另一个问题可能归结于您的列表切片。请记住,切片符号每次都涉及创建一个新列表,这意味着您将使用四个切片创建约 200,000,000 个新列表。现在我不确定这会更快,但是您可以在不复制的情况下实现相同的行为,例如:

sum(t_corr[z-10:z])

可以替换为

sum(t_coor[i] for i in range(z, 10))

再一次,把它改成你真正想要的;这只是一个概念片。

让我知道这是否有帮助!

【讨论】:

  • 您也可以尝试利用例如r1[x]r1[x + 1],据我所知,这是 t_corr[x+1] - t_corr[x-9]
  • 非常感谢 cmets。我会尝试合并这些,看看是否能获得任何性能提升。
  • @user3765371 正如 Ulrich 所说,分析器可能非常有用。我对 numpy/scipy 几乎没有经验,但如果分析器显示您将大部分时间都花在这些模块上,那么进行这些改进将无济于事:)
  • @user3765371 我有点得意忘形并添加了另一个建议,使用 cython 将您的脚本编译为本机二进制文件。如果你设法让它编译,那么我觉得这可能是一个很好的改进!
  • 这些切片是 NumPy 数组切片,而不是列表切片。 NumPy 切片生成视图,而不是副本。 (我有点惊讶你知道 Cython,但不知道 NumPy。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-12
  • 2016-11-27
  • 2017-10-13
  • 2016-01-14
  • 2011-04-17
相关资源
最近更新 更多