MATLAB - 返回对应于同类元素的总和矩阵
MATLAB - Returning a matrix of sums of elements corresponding to the same kind
概览
一个n×m
矩阵A
和一个n×1
向量Date
是函数S = sumdate(A,Date)
的输入。
函数 returns 一个 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)
相同,我们有
S(2,1)
和S(3,1)
都等于A(2,1)
和A(3,1)
的和
S(2,2)
和S(3,2)
都等于A(2,2)
和A(3,2)
的和。
因为元素Date(1)
、Date(7)
、Date(8)
和Date(9)
相同,所以我们有
S(1,1)
、S(7,1)
、S(8,1)
、S(9,1)
等于A(1,1)
、A(7,1)
、A(8,1)
, A(9,1)
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) = 7
和S(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
我在我的电脑上使用 A
和 Date
测试了它,这些属性:
size(A) = [33055 400];
size(Date) = [33055 1];
length(unique(Date)) = 2645;
我的电脑执行该任务大约需要 1.25 秒。
这个任务在我的项目中执行了数十万次,因此我的代码太耗时了。我认为如果我能消除上面的 for 循环,性能会得到提升。
我发现了一些内置函数可以执行特殊类型的求和,例如 accumarray
或 cumsum
,但我仍然不知道如何消除 for 循环。
非常感谢您的帮助。
您可以使用 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: 这将使用比 for 循环解决方案更多的内存(subs
的元素数量是 A
的两倍),但可能会给你显着的加速。
注#2:如果您使用的 MATLAB 版本早于 R2015a,则不会有 repelem
. Instead you can replace that line using kron
(or one of the other solutions here):
kron((1:size(A, 2)).', ones(size(A, 1), 1))
概览
一个n×m
矩阵A
和一个n×1
向量Date
是函数S = sumdate(A,Date)
的输入。
函数 returns 一个 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)
相同,我们有S(2,1)
和S(3,1)
都等于A(2,1)
和A(3,1)
的和
S(2,2)
和S(3,2)
都等于A(2,2)
和A(3,2)
的和。
因为元素
Date(1)
、Date(7)
、Date(8)
和Date(9)
相同,所以我们有S(1,1)
、S(7,1)
、S(8,1)
、S(9,1)
等于A(1,1)
、A(7,1)
、A(8,1)
,A(9,1)
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) = 7
和S(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
我在我的电脑上使用 A
和 Date
测试了它,这些属性:
size(A) = [33055 400];
size(Date) = [33055 1];
length(unique(Date)) = 2645;
我的电脑执行该任务大约需要 1.25 秒。
这个任务在我的项目中执行了数十万次,因此我的代码太耗时了。我认为如果我能消除上面的 for 循环,性能会得到提升。
我发现了一些内置函数可以执行特殊类型的求和,例如 accumarray
或 cumsum
,但我仍然不知道如何消除 for 循环。
非常感谢您的帮助。
您可以使用 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: 这将使用比 for 循环解决方案更多的内存(subs
的元素数量是 A
的两倍),但可能会给你显着的加速。
注#2:如果您使用的 MATLAB 版本早于 R2015a,则不会有 repelem
. Instead you can replace that line using kron
(or one of the other solutions here):
kron((1:size(A, 2)).', ones(size(A, 1), 1))