0

这与我之前提出的问题相似,但略有不同:

所以我在matlab中有一个非常大的结构数组。假设,为了论证,为了简化情况,假设我有类似的东西:

structure(1).name, structure(2).name, structure(3).name structure(1).returns, structure(2).returns, structure(3).returns(在我的真实程序中,我有 647 个结构)

进一步假设 structure(i).returns 是一个向量(非常大的向量,大约 2,000,000 个条目),并且出现了一个条件,我想从 structure(i).returns 中删除所有 i 的第 j 个条目。你怎么做到这一点?或者更确切地说,您如何合理快速地做到这一点?我已经尝试了一些东西,但它们都非常慢(我将在一秒钟内展示它们)所以我想知道社区是否知道更快的方法来做到这一点。

我以两种不同的方式解析了我的数据;第一种方法将所有内容都保存为单元格数组,但由于对我来说效果不佳,我再次解析数据并将所有内容都放置为向量。

我实际上在做的是尝试删除 NaN 数据,以及我的数据文件的同一相应行中的所有数据,然后在应用 Hampel 过滤器后做同样的事情。在此尝试中,我的代码的相关部分是:

for i=numStock+1:-1:1
    for j=length(stock(i).return):-1:1
        if(isnan(stock(i).return(j)))
            for k=numStock+1:-1:1
                stock(k).return(j) = [];
            end
        end
    end
    stock(i).return = sort(stock(i).return);
    stock(i).returnLength = length(stock(i).return);
    stock(i).medianReturn = median(stock(i).return);
    stock(i).madReturn = mad(stock(i).return,1);
end;

for i=numStock:-1:1
    for j = length(stock(i+1).volume):-1:1
        if(isnan(stock(i+1).volume(j)))
            for k=numStock:-1:1
               stock(k+1).volume(j) = [];
            end
        end
    end
    stock(i+1).volume = sort(stock(i+1).volume);
    stock(i+1).volumeLength = length(stock(i+1).volume);
    stock(i+1).medianVolume = median(stock(i+1).volume);
    stock(i+1).madVolume = mad(stock(i+1).volume,1);
end;



for i=numStock+1:-1:1
    for j=stock(i).returnLength:-1:1
        if (abs(stock(i).return(j) - stock(i).medianReturn) > 3*stock(i).madReturn)
            for k=numStock+1:-1:1
                stock(k).return(j) = [];
            end
        end;
    end;
end;

for i=numStock:-1:1
    for j=stock(i+1).volumeLength:-1:1
        if (abs(stock(i+1).volume(j) - stock(i+1).medianVolume) > 3*stock(i+1).madVolume)
            for k=numStock:-1:1
                stock(k+1).volume(j) = [];
            end
        end;
    end;
end;

但是,这会返回错误:

“矩阵索引超出删除范围。

失败错误(第 110 行)stock(k).return(j) = [];"

因此,我尝试将所有内容解析为向量。然后我决定在构建结构数组之前尝试删除向量中的适当条目。这不会返回错误,但速度很慢:

%% Delete bad data, Hampel Filter

% Delete bad entries
id=strcmp(returns,'');
returns(id)=[];
volume(id)=[];
date(id)=[];
ticker(id)=[];
name(id)=[];
permno(id)=[];
sp500(id) = [];

id=strcmp(returns,'C');
returns(id)=[];
volume(id)=[];
date(id)=[];
ticker(id)=[];
name(id)=[];
permno(id)=[];
sp500(id) = [];

% Convert returns from string to double
returns=cellfun(@str2double,returns);
sp500=cellfun(@str2double,sp500);

% Delete all data for which a return is not a number
nanid=isnan(returns);
returns(nanid)=[];
volume(nanid)=[];
date(nanid)=[];
ticker(nanid)=[];
name(nanid)=[];
permno(nanid)=[];

% Delete all data for which a volume is not a number
nanid=isnan(volume);
returns(nanid)=[];
volume(nanid)=[];
date(nanid)=[];
ticker(nanid)=[];
name(nanid)=[];
permno(nanid)=[];

% Apply the Hampel filter, and delete all data corresponding to
% observations deleted by the filter.

medianReturn = median(returns);
madReturn = mad(returns,1);

for i=length(returns):-1:1
    if (abs(returns(i) - medianReturn) > 3*madReturn)
        returns(i) = [];
        volume(i)=[];
        date(i)=[];
        ticker(i)=[];
        name(i)=[];
        permno(i)=[];
    end;
end

medianVolume = median(volume);
madVolume = mad(volume,1);

for i=length(volume):-1:1
    if (abs(volume(i) - medianVolume) > 3*madVolume)
        returns(i) = [];
        volume(i)=[];
        date(i)=[];
        ticker(i)=[];
        name(i)=[];
        permno(i)=[];
    end;
end

正如我所说,这很慢,可能是因为我在一个非常大的数据集上使用了 for 循环;但是,我不确定其他人会如何做到这一点。很抱歉这篇巨大的帖子,但有没有人建议我如何以合理的方式去做我所要求的事情?

编辑:我应该补充一点,让向量方法工作可能更可取,因为我的目标是将所有返回向量放入一个矩阵并将所有体积向量放入一个矩阵并对它们执行 PCA,我不知道我会如何使用单元阵列(或者即使 princomp 可以在单元阵列上工作)。

EDIT2:我已经更改了代码以符合您的建议(尽管我确实决定放弃速度并保持 for 循环以保持结构数组,因为重新解析这些数据在时间上会更糟)。新的代码片段是:

stock_return = zeros(numStock+1,length(stock(1).return));

for i=1:numStock+1
    for j=1:length(stock(i).return)
        stock_return(i,j) = stock(i).return(j);
    end
end

stock_return = stock_return(~any(isnan(stock_return)), : );

这会返回一个索引超出矩阵尺寸错误,我不知道为什么。有什么建议么?

4

1 回答 1

1

我找不到一种方便的方法来处理结构,因此我将重组代码,以便它使用数组而不是结构。
例如,而不是stock(i).return(j)我会做stock_returns(i,j).

我在部分代码中向您展示了如何摆脱 for 循环。

假设我们处理这段代码:

for j=length(stock(i).return):-1:1
    if(isnan(stock(i).return(j)))
        for k=numStock+1:-1:1
            stock(k).return(j) = [];
        end
    end
end

现在,删除包含任何NaN数据的列如下所示:

stock_return = stock_return(:, ~any(isnan(stock_return)) );

至于与 medianVolume 的绝对差值,可以写一段类似的代码:

% stock_return_length is a scalar
% stock_median_return is a column vector (eg. [1;2;3])
% stock_mad_return is also a column vector.

median_return = repmat(stock_median_return, stock_return_length, 1);
is_bad = abs(stock_return - median_return) > 3.* stock_mad_return;
stock_return = stock_return(:, ~any(is_bad));

使用标量stock_return_length当然意味着返回长度是相同的,但无论如何你都隐含地假设它在你的原始代码中。

我回答的重点是使用any. 逻辑索引本身是不够的,因为在您的原始代码中,如果其中任何一个值是错误的,您将删除所有值。

参考任何: http: //www.mathworks.co.uk/help/matlab/ref/any.html


如果你想保留原始结构,所以你坚持使用 stock(i).return,你可以使用基本相同的方案来加速你的代码,但你只能少一个 for 循环,这意味着你的程序将会慢很多。

于 2012-12-14T11:12:16.533 回答