Performance 删除一个";“世界其他地区”;从结构数组

Performance 删除一个";“世界其他地区”;从结构数组,performance,matlab,for-loop,runtime-error,Performance,Matlab,For Loop,Runtime Error,这与我之前提出的一个问题类似,但略有不同: 所以我在matlab中有一个非常大的结构数组。为了便于论证,为了简化情况,假设我有这样的东西: 结构(1).名称,结构(2).名称,结构(3).名称结构(1).返回,结构(2).返回,结构(3).返回(在我的实际程序中,我有647个结构) 进一步假设结构(i).returns是一个向量(非常大的向量,大约2000000个条目),并且出现了一个条件,我想从结构(i)中删除第j个条目。你是怎么做到的?或者更确切地说,你是如何做到这一点的?我试过一些方法,但

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

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

结构(1).名称,结构(2).名称,结构(3).名称结构(1).返回,结构(2).返回,结构(3).返回(在我的实际程序中,我有647个结构)

进一步假设结构(i).returns是一个向量(非常大的向量,大约2000000个条目),并且出现了一个条件,我想从结构(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行) 股票(k).收益率(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循环以保留结构数组,因为重新分析这些数据在时间上会更糟)。新的snipet代码是:

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)), : );

这会返回一个索引超过矩阵维数的错误,我不知道为什么。有什么建议吗?

我找不到一种方便的方法来处理结构,因此我将重新构造代码,使其只使用数组而不是结构。
例如,我会做
stock\u returns(i,j)
而不是
stock(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\u return\u length
使用标量当然意味着返回长度是相同的,但无论如何,您都会在原始代码中隐式地假定它

我回答的要点是使用
any
。逻辑索引本身是不够的,因为在原始代码中,如果任何值不正确,则删除所有值

引用任何:



如果你想保留原来的结构,那么就坚持使用stock(i).return,你可以使用基本相同的方案来加速你的代码,但你只能少摆脱一个for循环,这意味着您的程序将大大降低速度。

为了提高代码的速度,您需要通过使用matlab中的向量运算来避免使用for循环。我的意思是,这很好,我很乐意。但是我如何在不使用for循环的情况下执行上面所示的操作呢?我真的不知道没有它怎么做。好吧,你的真实情况是什么?只是isnan吗?第一部分,是的。但对于第二部分,我有一个abs(volume(I)-medianVolume)>3*madVolume条件(对于返回值也类似),我想删除与该条件成立的点对应的所有数据。如果没有for-loop方法,我真的不知道该怎么做,而且可能是将这件事拖慢到爬行的方法。对于edit2,我的答案是评论。好的,我明白了,这实际上与我尝试的矢量化方法(我在原始消息中的第二次尝试)配合得很好。这对其他向量也有效吗?也就是说,如果我使用is_bad来确定我要删除哪些索引,那么这是否也适用于卷?简言之,要从volume中删除相应的条目,volume=volume(:,~any(is_bad))的工作原理是否相同?如果没有,有没有办法确定哪些指数从收益中删除,并从成交量中删除这些相同的指数?请注意,这里的重要技巧是
any
。你需要使用它,而不仅仅是逻辑索引。好吧,我来试试看会发生什么。祝我好运嗯,它加快了代码的速度,但现在你的建议给了我一个错误:“索引超过了矩阵维度。失败中的错误(第114行)stock_return=stock_return(~any(isnan(stock_return)),:);”(我将其更改为删除行而不是列,但这并不重要)。为什么会返回索引超过矩阵维数的错误?编辑:见我的原始帖子中的编辑2。是的,这应该很重要!如果你改变它,那么你说你扔掉了一只股票i的完整的收益序列,如果它有NaN的话。当然,这对于matlab来说也没有意义,因为表达式是不可改变的。如果你想改变它,你至少需要做
stock\u return=