2011-07-22 17 views
1

2つの行列の要素を一致させる際に問題があります。最初の要素はismemberを使用して一致させることができますが、2番目の要素は範囲内でなければなりません。簡単にするために一致ID + Matlabの行列内の数値を見つける

% col1 is integerID, col2 is a number.  -->col1 is Countrycode, col2 is date 
bigmat = [ 600 2 
      600 4 
      800 1 
      800 5 
      900 1] ; 

% col1 is integerID, col2 is VALUE, col2 is a range -->value is Exchange rate 
datamat = {... 
      50 0.1 [2 3 4 5 6]  % 2:6 
      50 0.2 [9 10 11]   % 9:11 
      600 0.01 [1 2 3 4]   % 1:4 
      600 0.2 [8 9 10]   % 8:10 
      800 0.12 [1]    % 1:1 
      800 0.13 [3 4]    % 3:4 
      900 0.15 [1 2]  } ; % 1:2 

I need the answer as: 
    ansmat = [ 600 2 0.01 
       600 4 0.01 
       800 1 0.12 
       800 5 nan    % even deleting this row is fine 
       930 1 0.15 ] ; 

:matrix_1から

  1. すべてintIDsがmatrix_2に存在する以下の例を参照してください。
  2. 範囲内の数字は日付です!範囲内では、これらの数値は連続しています。[1 2 ... 5]
  3. IDの場合、次の行の日付は連続していません。たとえば、次の行に[1 2 3 4]と[8 9 10]が表示されます。

bigmatは巨大なマトリックスです! 300,000〜500,000行になるため、ベクトル化されたコードが評価されます。 datamatはおよそ5000行以下です。セルを行列に変換することができます。各行について、最小値と最大値を持っています。 3列は最小値:最大値です。ありがとう!ここで

答えて

0

は、一つの可能​​な実装である:

%# data matrices 
q = [ 
    600 2 
    600 4 
    800 1 
    800 5 
    900 1 
]; 
M = { 
    50 0.1 [2 3 4 5 6] 
    50 0.2 [9 10 11] 
    600 0.01 [1 2 3 4] 
    600 0.2 [8 9 10] 
    800 0.12 [1] 
    800 0.13 [3 4] 
    900 0.15 [1 2] 
}; 

%# build matrix: ID,value,minDate,maxDate 
M = [cell2num(M(:,1:2)) cellfun(@min,M(:,3)) cellfun(@max,M(:,3))]; 

%# preallocate result 
R = zeros(size(M,1),3); 

%# find matching rows 
c = 1;    %# counter 
for i=1:size(q,1) 
    %# rows indices matching ID 
    ind = find(ismember(M(:,1),q(i,:))); 

    %# out of those, keep only those where date number is in range 
    ind = ind(M(ind,3) <= q(i,2) & q(i,2) <= M(ind,4)); 

    %# check if any 
    num = numel(ind); 
    if num==0, continue, end 

    %# extract matching rows 
    R(c:c+num-1,:) = [M(ind,1) repmat(q(i,2),[num 1]) M(ind,2)]; 
    c = c + num; 
end 

%# remove excess 
R(c:end,:) = []; 

予想通りの結果:

>> R 
R = 
      600   2   0.01 
      600   4   0.01 
      800   1   0.12 
      900   1   0.15 
+0

おかげアムロを

とにかく、あなたのような何かを試すことができるかもしれしかし、Forループには多くの時間がかかります。私は何とかベクトル化されたアプローチを使用できるかどうかを確認しようとしています。 datamatの3番目の列には、すでに最小値と最大値が別の列として格納されています。私は何とかコードを高速化するためにそれらを使用できるかどうかはわかりません。ありがとう。 – Maddy

+0

@Maddy:あなたは正しいです、私は説明したのと同じサイズのランダムなデータ(300Kと5K)でそれをテストしました。それは70秒かかりました。また、最小/最大については、代わりに 'M'を使用していましたが、大きな違いがあるとは思えません。私はもう一度試してみて、時間を改善できるかどうか確認してください。) – Amro

-1

私は.. 2番目のエントリは、 '600 4 0.02' でなければなりません理解して完全にわからないんだけど?そのように一緒にあなたがあなたの行列から必要な行を持っていたら、その後、あなたがそれらを連結することができ

% grab first column 
col = bigmat(:, 1); 

% find all entries in column that are equal to ID 
rel = (col == id); 

% retrieve just those rows 
rows = bigmat(rel, :); 

result = [rowsA(1:3) rowsB(2) rowsC(5:6)]; 
+0

安倍、600 intIDは[1 2 3 4]の値が0.01で、datamatのように表示されます。よりよい例は、日付が[734410 734411 734412 734413]の場合、600が0.01の値を持つことです。ご返事ありがとうございます。 – Maddy

関連する問題