MATLAB - 选举对应于相同种类

问题描述:

概述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

你可以用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