2017-08-22 48 views
1

概述MATLAB - 選舉對應於相同種類

一種n×m矩陣A元素的總和的矩陣和矢量n×1Date功能S = sumdate(A,Date)的輸入端。

該函數返回n×m向量S,使得S中的所有行對應於同一日期的A行的總和。

例如,如果

A = [1 2 7 3 7 3 4 1 9 
    6 4 3 0 -1 2 8 7 5]'; 
Date = [161012 161223 161223 170222 160801 170222 161012 161012 161012]'; 

然後我希望返回的矩陣S

S = [15 9 9 6 7 6 15 15 15; 
    26 7 7 2 -1 2 26 26 26]'; 
  • 因爲元素Date(2)Date(3)是相同的,我們有

    1. S(2,1)S(3,1)都等於的A(2,1)A(3,1)
    2. S(2,2)S(3,2)都等於的A(2,2)A(3,2)總和的總和。
  • 由於元件Date(1)Date(7)Date(8)Date(9)是相同的,我們有

    1. S(1,1)S(7,1)S(8,1)S(9,1)等於的A(1,1)A(7,1)A(8,1)A(9,1)

    2. 總和
    3. S(1,2)S(7,2)S(8,2)S(9,2)等於的A(1,2)A(7,2)A(8,2)總和,A(9,2)

同爲S([4,6],1)S([4,6],2)

作爲元件Date(5)不重複,所以S(5,1) = A(5,1) = 7S(5,2) = A(5,2) = -1


我寫的代碼到目前爲止

這是我對這個任務的代碼試試。

function S = sumdate(A,Date) 
    S = A; %Pre-assign S as a matrix in the same size of A. 
    Dlist = unique(Date); %Sort out a non-repeating list from Date 
    for J = 1 : length(Dlist) 
     loc = (Date == Dlist(J)); %Compute a logical indexing vector for locating the J-th element in Dlist 
     S(loc,:) = repmat(sum(S(loc,:)),sum(loc),1); %Replace the located rows of S by the sum of them 
    end 
end 

我使用ADate具有這些屬性測試它在我的電腦上:

size(A) = [33055 400]; 
size(Date) = [33055 1]; 
length(unique(Date)) = 2645; 

花了我的電腦約1.25秒內執行任務。

此任務在我的項目中執行了數十萬次,因此我的代碼太耗時。如果我能消除上面的for循環,我認爲性能會提高。

我發現了一些內置函數,它們可以執行accumarraycumsum等特殊類型的總和,但我仍然對如何消除for循環沒有任何建議。

我將不勝感激您的幫助。

+3

注:你應該使用'.''轉置矩陣,而不是共軛複數''' – Wolfie

+0

非常感謝你爲您的編輯和建議。你是對的,我應該使用'。''來代替,因爲在這種情況下我不需要任何共軛,輸入包含複數。 – Leba

+0

沒問題,我最終爲你做了編輯,但在將來嘗試使用「代碼格式化」而不是**粗體格式**時,如果在文本中有代碼,它會使事情變得更加清晰 – Wolfie

回答

3

你可以用accumarray來做到這一點,但是你需要生成一組行和列的下標到A來做到這一點。具體方法如下:

[~, ~, index] = unique(Date); % Get indices of unique dates 
subs = [repmat(index, size(A, 2), 1) ...   % repmat to create row subscript 
     repelem((1:size(A, 2)).', size(A, 1))]; % repelem to create column subscript 
S = accumarray(subs, A(:)); % Reshape A into column vector for accumarray 
S = S(index, :);    % Use index to expand S to original size of A 

S = 

    15 26 
    9  7 
    9  7 
    6  2 
    7 -1 
    6  2 
    15 26 
    15 26 
    15 26 

注1:這將使用更多的內存比您的循環液(subs將元素作爲A數的兩倍),但可以給你一個顯著加速。

注#2:如果您使用的是比R2015a更早的MATLAB版本,您將不會有repelem。相反,你可以替換使用kron(或其他解決方案here之一)該行:

kron((1:size(A, 2)).', ones(size(A, 1), 1)) 
+1

如果您不想「有'repelem'見[這裏](https://stackoverflow.com/questions/1975772/repeat-copies-of-array-elements-run-length-decoding-in-matlab) –

+0

@Jon:謝謝,我補充說這是一個說明。 – gnovice

+0

我的版本是2016a,我有足夠的內存,所以解決方案對我來說絕對沒問題。您的解決方案簡單高效。非常感謝你。 – Leba