MATLab Bootstrap没有for循环

时间:2014-08-08 09:09:44

标签: matlab statistics-bootstrap

昨天我在MATLab中实现了我的第一个引导程序。 (是的,我知道,因为循环是邪恶的。):

%data is an mxn matrix where the data should be sampled per column but there 
can be a NaNs Elements
%from the array (a column of data) n values are sampled nReps times

function result = bootstrap_std(data, n, nReps,quantil)

result = zeros(1,size(data,2));

for i=1:size(data,2)
    bootstrap_data = zeros(n,nReps);
    values = find(~isnan(data(:,i)));
    if isempty(values)
       bootstrap_data(:,:) = NaN;
    else
        for k=1:nReps
            bootstrap_data(:,k) = datasample(data(values,i),n);
        end
    end

    stat = zeros(1,nReps);

    for k=1:nReps
        stat(k) = nanstd(bootstrap_data(:,k));
    end

    sort(stat);
    result(i) = quantile(stat,quantil);      
end
end

可以看出,此版本按列方式工作。该算法可以实现应有的功能,但在数据大小增加时却非常慢。我现在的问题是:是否可以在不使用for循环的情况下实现此逻辑?我的问题是在这里我找不到以数据为单位进行采样的数据样本。或者是否有更好的功能使用?

我很高兴有任何提示或想法如何加快这种实施。

谢谢和最诚挚的问候!

斯蒂芬

2 个答案:

答案 0 :(得分:2)

您的实施中的瓶颈是

  1. 该函数在nanstd内花费了大量时间,这是不必要的,因为无论如何都要从样本中排除NaN值。
  2. 有很多函数按列操作,但是你需要花时间在列上循环并多次调用它们。
  3. 你多次拨打datasample,这是一个相对较慢的功能。使用randi创建索引的随机向量并使用它更快。
  4. 以下是我将如何编写函数(实际上我可能不会放在这么多注释中,我不会使用这么多的临时变量,但我现在正在这样做,所以你可以看到所有的步骤计算是)。

    function result = bootstrap_std_new(data, n, nRep, quantil)
    
        result = zeros(1, size(data,2));
    
        for i = 1:size(data,2)
            isbad = isnan(data(:,i));                   %// Vector of NaN values
            if all(isbad)
                result(i) = NaN;
            else
                data0 = data(~isbad, i);                %// Temp copy of this column for indexing
                index = randi(size(data0,1), n, nRep);  %// Create the indexing vector
                bootstrapdata = data0(index);           %// Sample the data
                stdevs = std(bootstrapdata);            %// Stdev of sampled data
                result(i) = quantile(stdevs, quantil);  %// Find the correct quantile
            end
        end
    
    end
    

    以下是一些时间

    >> data = randn(100,10);
    >> data(randi(1000, 50, 1)) = NaN;
    >> tic, bootstrap_std(data, 50, 1000, 0.5); toc
    Elapsed time is 1.359529 seconds.
    >> tic, bootstrap_std_new(data, 50, 1000, 0.5); toc
    Elapsed time is 0.038558 seconds.
    

    因此,这为您提供了35倍的加速。

答案 1 :(得分:0)

您的主要问题似乎是每列中的NaN数量/位置不同,因此除非您也可以对NaN进行采样,否则无法对完整矩阵起作用。但是,一些内部循环可以简化。

for k=1:nReps
    bootstrap_data(:,k) = datasample(data(values,i),n);
end

由于您正在使用替换品进行抽样,您应该能够做到:

bootstrap_data = datasample(data(values,i), n*nReps);
bootstrap_data = reshape(bootstrap_data, [n nReps]);

此外nanstd可以处理完整矩阵,因此无需循环:

stat = nanstd(bootstrap_data); % or nanstd(x,0,2) to change dimension

使用profile查看代码也值得查看瓶颈所在。