在MatLab中向量化嵌套循环

lbsnaicq  于 2022-11-15  发布在  Matlab
关注(0)|答案(1)|浏览(249)

我在MatLab中有一个“超级嵌套”循环来创建数组gamma。执行该循环需要很长时间。我希望你能帮我把环路矢量化。
以下是带有解释的代码:

rng default
clear 

%%%%%%%%%%%%%%%%%Parameters
L=2;
K=3;
n_draws=10^6;
mu_V=zeros(1, L+1);  
Sigma_V=eye(L+1);  
v_draws=mvnrnd(mu_V,Sigma_V,n_draws); %n_drawsx(L+1)
payoff=randn(n_draws, L+1); %n_drawsx(L+1)
v_upp=5;  
v_low=-5; 

%%%%%%%%%%%%%%%%Fill the array gamma
gamma=zeros(K+1,K+1,K+1,L+1,L+1); %allocate space for the array gamma
for k1=1:K+1 
    for k2=1:K+1
        for k3=1:K+1 
            for y=1:L+1  
                for y1=1:L+1
                    tic
                    integr=((nchoosek(K, (k1-1))*(((v_draws(:,1)-v_low).^(k1-1).*(v_upp-v_draws(:,1)).^(K-(k1-1)))./((v_upp-v_low).^K))).*...
                            (nchoosek(K, (k2-1))*(((v_draws(:,2)-v_low).^(k2-1).*(v_upp-v_draws(:,2)).^(K-(k2-1)))./((v_upp-v_low).^K))).*...
                            (nchoosek(K, (k3-1))*(((v_draws(:,3)-v_low).^(k3-1).*(v_upp-v_draws(:,3)).^(K-(k3-1)))./((v_upp-v_low).^K)))).*...
                             mvnpdf(v_draws,mu_V,Sigma_V).*...
                            (payoff(:,y)-payoff(:,y1)); %n_drawsx1  
                    gamma(k1,k2,k3,y,y1)=sum(integr)/n_draws; %average of elements of integr
                    toc
                end
            end
        end
    end
end

例如,对于K=3,执行时间大约为20秒。在我的实际锻炼中,K=50和它永远花费。

afdcj2ne

afdcj2ne1#

通过应用两种主要类型的改进,您可以从我的测试中节省约95%的运行时间
1.尽可能在最外层的循环中计算东西,这样等价的项就不会被多次计算。
1.向量处理内部的y1循环以删除它
v_uppv_lowv_draws之间的所有增量都是恒定的,因为这些向量在循环中不会改变,因此都可以在循环之外计算。mvnpdf也可以。
然后,代码如下所示:

gamma=zeros(K+1,K+1,K+1,L+1,L+1); %allocate space for the array gamma
v_delta = v_upp-v_low;
v_delta_upp1 = v_upp-v_draws(:,1);
v_delta_upp2 = v_upp-v_draws(:,2);
v_delta_upp3 = v_upp-v_draws(:,3);
v_delta_low1 = v_draws(:,1)-v_low;
v_delta_low2 = v_draws(:,2)-v_low;
v_delta_low3 = v_draws(:,3)-v_low;
MVN = mvnpdf(v_draws,mu_V,Sigma_V);
y1=1:L+1;
for k1=1:K+1 
    term1 = (nchoosek(K, (k1-1))*((v_delta_low1.^(k1-1).*v_delta_upp1.^(K-(k1-1)))./(v_delta.^K)));
    for k2=1:K+1
        term2 = (nchoosek(K, (k2-1))*((v_delta_low2.^(k2-1).*v_delta_upp2.^(K-(k2-1)))./(v_delta.^K)));
        for k3=1:K+1 
            term3 = (nchoosek(K, (k3-1))*((v_delta_low3.^(k3-1).*v_delta_upp3.^(K-(k3-1)))./(v_delta.^K)));
            integr = term1 .* term2 .* term3 .* MVN;
            for y=1:L+1  
                integrp = integr .* (payoff(:,y)-payoff(:,y1)); %n_drawsx1  
                gamma(k1,k2,k3,y,y1)=sum(integrp)/n_draws; %average of elements of integr                
            end
        end
    end
end

您可以通过注意如下内容来进一步改进这一点

  • 您在每个循环中计算nchoosek1:K+1,如果预先计算nchoosek值的数组,并在循环时只对其进行索引,可能会更快。
  • 每次循环迭代都要除以n_draws,再乘以mvnpdf项,这样做会不会更快?

然而,看着这样的事情,你会得到越来越少的回报。

相关问题