这是我模拟Levy动作的小脚本:
clear all;
clc; close all;
t = 0; T = 1000; I = T-t;
dT = T/I; t = 0:dT:T; tau = T/I;
alpha = 1.5;
sigma = dT^(1/alpha);
mu = 0; beta = 0;
N = 1000;
X = zeros(N, length(I));
for k=1:N
L = zeros(1,I);
for i = 1:I-1
L( (i + 1) * tau ) = L(i*tau) + stable2( alpha, beta, sigma, mu, 1);
end
X(k,1:length(L)) = L;
end
q = 0.1:0.1:0.9;
quant = qlines2(X, q, t(1:length(X)), tau);
hold all
for i = 1:length(quant)
plot( t, quant(i) * t.^(1/alpha), ':k' );
end
其中stable2
返回带有给定参数的stable random variable(对于这种情况,您可以将其替换为normrnd(mu, sigma)
,但这并不重要); qlines2
返回绘图所需的分位数。
但我不想在这里谈论数学。我的问题是这个实现很慢,我想加快速度。不幸的是,计算机科学不是我的主要领域 - 我听说过有关记忆,矢量化等方法的东西,还有很多其他技术,但我不知道如何使用它们。
例如,我非常确定我应该以某种方式替换这个污秽的双循环,但我不知道该怎么办。
编辑:也许我应该使用(并学习......)另一种语言(Python,C,任何功能)?我总是认为Matlab / OCTAVE是为数值计算而设计的,但如果改变了,那么对于哪一个?
答案 0 :(得分:4)
正如你所说,关键位是for循环,Matlab不喜欢那些,所以 vectorization 确实是关键字。 (与预先分配空间一起。
我只是稍微改变了你的循环部分,这样你就不必一遍又一遍地重置L
,而是将所有L
保存在一个更大的矩阵中(我也消除了{{ 1}}命令)。
length(L)
现在你已经可以看到循环中的L = zeros(N,I);
for k=1:N
for i = 1:I-1
L(k,(i + 1) * tau ) = L(k,i*tau) + normrnd(mu, sigma);
end
X(k,1:I) = L(k,1:I);
end
已经过时,这也意味着我们可以切换循环的顺序。这是至关重要的,因为X(k,1:I) = L(k,1:I);
- 步骤是递归的(取决于前一步骤),这意味着我们无法对此循环进行矢量化,我们只能对i
- 循环进行矢量化。
现在你的原始代码在我的机器上需要9.3秒,新代码仍然需要大约相同的时间)
k
但是现在我们可以应用矢量化,而不是循环所有行(L = zeros(N,I);
for i = 1:I-1
for k=1:N
L(k,(i + 1) * tau ) = L(k,i*tau) + normrnd(mu, sigma);
end
end
X = L;
上的循环),我们可以改为消除这个循环,并在“一次”执行所有行。
k
此代码在我的机器上仅需0.045秒。我希望你仍然能得到相同的输出,因为我不知道你在计算什么,但我也希望你能看到你如何进行矢量化代码。
PS:我刚刚注意到我们现在在整个列的最后一个示例中使用相同的随机数,这显然不是您想要的。 Instad你应该生成一个随机数的整个向量,例如:
L = zeros(N,I);
for i = 1:I-1
L(:,(i + 1) * tau ) = L(:,i*tau) + normrnd(mu, sigma); %<- this is not yet what you want, see comment below
end
X = L;
PPS:好问题!