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 エントリ) であり、すべての i について structure(i).returns から j 番目のエントリを削除する条件が発生したとします。これどうやってやるの?というか、どうすればこれをかなり速く行うことができますか? 私はいくつかのことを試しましたが、それらはすべて非常に遅いです (すぐに説明します) ので、コミュニティがこれを行うためのより高速な方法を知っているかどうか疑問に思っていました.

データを 2 つの異なる方法で解析しました。最初の方法では、すべてがセル配列として保存されていましたが、うまく機能していなかったため、データを再度解析し、すべてをベクトルとして配置しました。

私が実際に行っているのは、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 ループを使用しているためです。ただし、他にどのようにこれを行うかはわかりません。巨大な投稿で申し訳ありませんが、私が求めていることを合理的な方法で行う方法について誰か提案がありますか?

EDIT:ベクトルメソッドを機能させることがおそらく望ましいことを追加する必要があります。私の目的は、すべてのリターンベクトルをマトリックスに入れ、すべてのボリュームベクトルをマトリックスに入れ、それらに対して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 ループを 1 つ減らすことしかできません。つまり、プログラムは大幅に遅くなります。

于 2012-12-14T11:12:16.533 に答える