这类似于我之前提出的问题,但略有不同:
所以我在matlab中有一个非常大的结构数组。假设为了论证,为了简化情况,假设我有类似的东西:
结构(1).name,structure(2).name,structure(3).name structure(1).returns,structure(2).returns,structure(3).returns(在我的真实程序中我有647结构)
进一步假设结构(i).returns是一个向量(非常大的向量,大约2,000,000个条目),并且条件出现在我想从结构(i)中删除第j个条目的地方。所有i的返回。你怎么做到这一点?或者更确切地说,你如何快速地做到这一点?我尝试了一些东西,但它们都非常慢(我会在一秒钟内展示它们)所以我想知道社区是否知道更快的方法来做到这一点。
我以两种不同的方式解析了我的数据;第一种方法是将所有内容保存为单元格数组,但由于事情对我来说效果不佳,我再次解析数据并将所有内容都放在矢量中。
我实际上在做的是尝试删除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).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-loops以保持结构数组,因为重新分析这些数据会更加节省时间)。新代码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)), : );
这会返回索引超出矩阵维度的错误,我不知道为什么。有什么建议吗?
答案 0 :(得分: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循环,这意味着你的程序会慢得多。