【问题标题】:Optimizing code, removing "for loop"优化代码,去掉“for循环”
【发布时间】:2014-03-05 06:10:17
【问题描述】:

按照 Brownlees & Gallo 2006(如果您可能感兴趣的话),我正在尝试从刻度数据系列中删除异常值。

代码运行良好,但考虑到我正在处理非常长的向量(最大的向量有 20m 观察,并且在 20h 后它没有完成计算)我想知道如何加快它。

到目前为止我所做的是:
我将时间和日期格式更改为数字双精度,我发现它节省了相当多的处理时间和大量内存。
我为向量分配了内存:

[n] = size(price);
 x = price;
    score = nan(n,'double');           %using tic and toc I saw that nan requires less time than zeros
    trimmed_mean = nan(n,'double');
    sd = nan(n,'double');
    out_mat = nan(n,'double');

这是我想删除的循环。我读到向量化会加快很多,尤其是使用长向量。

for i = k+1:n
    trimmed_mean(i) = trimmean(x(i-k:i-1 & i+1:i+k),10,'round');  %trimmed mean computed on the 'k' closest observations to 'i' (i is excluded)
    score(i) = x(i) - trimmed_mean(i);
    sd(i) = std(x(i-k:i-1 & i+1:i+k)); %same as the mean
    tmp = abs(score(i)) > (alpha .* sd(i) + gamma);
    out_mat(i) = tmp*1;
end

这就是我想要做的事情

trimmed_mean=trimmean(regroup_matrix,10,'round',2);
score=bsxfun(@minus,x,trimmed_mean);
sd=std(regroup_matrix,2);
temp = abs(score) > (alpha .* sd + gamma);
out_mat = temp*1;

但鉴于我对 Matlab 完全陌生,我不知道如何正确构建相邻观测值的矩阵。我只是觉得它的形状应该是:regroup_matrix= nan (n,2*k)

编辑:具体来说,我想要做的(但我做不到)是:
给定“x”中每个观察“i”的列向量“x”(n,1),我想将“k”个相邻观察带到“i”(从 ik 到 i-1 和从 i+1 到 i +k) 并将这些观察结果作为矩阵 (n, 2*k) 的行。

编辑 2:我对代码进行了一些更改,我认为我离解决方案越来越近了。我针对我现在认为的问题发布了另一个问题:
Matlab: Filling up matrix rows using moving intervals from a column vector without a for loop

我现在要做的是:

[n] = size(price,1);
x = price;
[j1]=find(x);
matrix_left=zeros(n, k,'double');
matrix_right=zeros(n, k,'double');
toc
matrix_left(j1(k+1:end),:)=x(j1-k:j1-1);

matrix_right(j1(1:end-k),:)=x(j1+1:j1+k);

matrix_group=[matrix_left matrix_right];
trimmed_mean=trimmean(matrix_group,10,'round',2);
score=bsxfun(@minus,x,trimmed_mean);
sd=std(matrix_group,2);
temp = abs(score) > (alpha .* sd + gamma);
outmat = temp*1;

我在创建 matrix_left 和 matrix_right 时遇到问题。 我用于索引的 j1 是一个列向量,其中包含价格观察值的索引。输出很简单

j1=[1:1:n]

price 是大小为 (n,1) 的 double 列向量

【问题讨论】:

  • x 似乎是一个向量,但x(i,tmp) = price(i-1,tmp) 可以将其扩展为二维矩阵。这是故意的吗?
  • k 未初始化。
  • @aschepler 不是故意的,是错字。 k 已初始化,我在调用函数时将其作为参数插入。 alpha 和 gamma 相同。
  • “regroup_matrix”初始化后,您想为其分配什么值?
  • @McMa 矩阵的每一行都应该由 x 的以下元素组成(i-k:i-1 & i+1:i+k)。如果具体可以帮助我目前使用 k=5。我认为要走的路是建立两个独立的矩阵,然后将它们合并起来。

标签: matlab filtering vectorization


【解决方案1】:

对于您的重塑,您可以执行以下操作:

idxArray = bsxfun(@plus,(k:n)',[-k:-1,1:k]);
reshapedArray = x(idxArray);

【讨论】:

  • 非常感谢,这是正确的方法。我只是稍微修改了它以适应我的需要,你编写代码的方式也是负索引(对于前 k 个观察)和系列索引之外(对于最后 k 个观察)。
【解决方案2】:

感谢 Jonas 为我指明了前进的方向,我想出了这个:

idxArray_left=bsxfun(@plus,(k+1:n)',[-k:-1]);           %matrix with index of left neighbours observations
idxArray_fill_left=bsxfun(@plus,(1:k)',[1:k]);          %for observations from 1:k I take the right neighbouring observations, this way when computing mean and standard deviations there will be no problems.
matrix_left=[idxArray_fill_left; idxArray_left];        %Just join the two matrices and I have the complete matrix of left neighbours
idxArray_right=bsxfun(@plus,(1:n-k)',[1:k]);            %same thing as left but opposite.
idxArray_fill_right=bsxfun(@plus,(n-k+1:n)',[-k:-1]);
matrix_right=[idxArray_right; idxArray_fill_right];      
idx_matrix=[matrix_left matrix_right];                  %complete index matrix, joining left and right indices
neigh_matrix=x(idx_matrix);                             %exactly as proposed by Jonas, I fill up a matrix of observations from 'x', following idx_matrix indexing
trimmed_mean=trimmean(neigh_matrix,10,'round',2);
score=bsxfun(@minus,x,trimmed_mean);
sd=std(neigh_matrix,2);
temp = abs(score) > (alpha .* sd + gamma);
outmat = temp*1;  

再次感谢乔纳斯。你真的让我很开心!
也感谢所有看过这个问题并试图提供帮助的人!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-12
    • 1970-01-01
    • 2020-02-18
    • 2019-05-31
    • 2011-03-12
    • 1970-01-01
    • 1970-01-01
    • 2019-01-11
    相关资源
    最近更新 更多