1

我想通过以下与非中心卡方分布相关的规则生成一个长度为 N 的随机序列 x:

x n+1ν 2 (λx n )

其中 ν 是表示自由度的给定常数,λ 也是预先指定的,λ 和 x n的乘积是非中心参数,x 1应该是给定的。我编写了以下代码来生成这样的序列和运行时间,x 1 =0.04,ν=0.005,λ=100 和 N=1e5:

tic;
N = 1e5;
x = zeros(1,N);
x(1) = 0.04;
nu = 0.005;
lambda = 100;
for i = 1:N-1
    x(i+1) = ncx2rnd(nu,lambda*x(i));
end
toc;

为了说明我的问题,我测试了另一个与上面不同的示例。在这里,我考虑从分布 χ ν 2 (λ)生成 N=1e5 个样本,其中 ν=0.005 和 λ=100:

tic;
N = 1e5;
x = zeros(1,N);
nu = 0.005;
lambda = 100;
for i = 1:N
    x(i) = ncx2rnd(nu,lambda);
end
toc;

tic;
N = 1e5;
nu = 0.005;
lambda = 100;
x = ncx2rnd(nu,lambda*ones(1,N));
toc;

这两种方法是等效的。然而,事实证明,不使用 for 循环的第二种方法比第一种方法快得多。两个例子的不同之处在于,在第二个例子中,生成一些样本的规则不需要先前样本的信息,而在第一个例子中不是这样,因此可以同时生成所有样本,而无需使用for循环。基于此,我想知道避免 for-loop 是否会加速代码执行。那么当对先前样本的依赖规则是明确的时,是否会有任何 MATLAB 内置函数来生成第一个示例中所示的随机序列而不使用 for 循环?如果规则是线性的,我知道该函数filter将是一个可能的选择,那么像第一个示例这样的情况呢?

4

1 回答 1

2

从逻辑上讲,如果不进行迭代,就不可能迭代计算。如果x(n+1)是依赖x(n)那么你必须先计算x(n),这里没有“聪明的把戏”。

这只是让我们优化循环内的计算,特别是ncx2rnd. 与大多数 MATLAB 内置函数一样,它已经相当简洁和高性能,但有一些事情需要考虑。请注意,我要建议的内容涉及使用edit ncx2nrd来查看这个包含 MathWorks 版权下代码的内置函数,我只是注意观察它是如何工作的。

  1. 有一些输入检查可以处理大小不正确的输入和/或负值输入。如果您可以自己承担验证的负担(即您知道您的输入是有效的),那么您可以将函数简化为单一的数学运算:

    % function r = ncx2rnd(v,delta)
    r = 2.*randg(poissrnd(delta./2, sizeOut)) + 2.*randg(v./2,sizeOut);
    

    运行这个独立运行可以节省大约 20% 的处理时间,这是用于输入验证(带有名义上的N=1e5)。

  2. 在 MathWorks 语法中,delta等于 your lambda*x(i),包括的另一个术语v与 your 无关x,因此您可以在循环之外计算它,即将对 的调用之一向量化randg。再次使用N=1e5它可以节省 25% 左右的总时间。

结果将意味着对您的示例进行此更改:

% Common inputs
N = 1e5;
nu = 0.1;
lambda = 0.1;

% Baseline example
x = zeros(1,N);
x(1) = 0.04;
for i = 1:N-1
    x(i+1) = ncx2rnd(nu,lambda*x(i));
end

% ~25% faster alternative, with no input validation and partially vectorised
x = zeros(1,N);
x(1) = 0.04;
vTerm = 2.*randg(nu./2, [1,N]);
for i = 1:N-1
    x(i+1) = 2.*randg(poissrnd(lambda*x(i)./2, [1,1])) + vTerm(i);
end
于 2021-07-08T11:32:08.613 回答