用于 3D 矩阵的 Matlab Accumarray
Matlab Accumarray for 3D matrix
我真的希望文档能更清楚地说明在 Matlab 中将 accumarray 用于 N 维大小矩阵。无论如何,我在这里完全困惑并寻求一些建议。这是挑战:
我有一个 3D 数据矩阵。
- ROWS 是个别河流
- 列是观察日期
- PAGES为数据采集的时间间隔
对于这个例子,我们假设每个观察值是在 5 分钟的时间间隔内流过仪表的水量。但是,我现在希望将数据重新采样为 N 分钟的间隔(显然是 5 的倍数)。让我们选择 NMINS = 15.
所以,我想做的是在 NMINS 分钟间隔内求出水量的总和或平均值。也就是说,ROWS 和 COLUMNS 不会改变,但 PAGES 的维度和值将是 decimated/aggregated.
我可以获得页面的分组值。也就是说,我需要分组的值。如果一天是一条河流,没问题。但是,我有几百天,几十条河。
我已经走到这一步了:
创建测试时间向量
NMINS = 15; % Bucket by every 15 mins or 20, etc.
N5MINS = 5 * 12 * 24 * 2; % Keep small - Two days of 5 min datenums
dnums = datenum(2016,3,20,0,0:5:N5MINS,0);
% Trim dnums to start at random time for edge case and keep only mins
mins = rem(dnums(25:end-30),1)'; % Create column vector
为测试创建随机矩阵
rng(123); % Set seed for reproducibility
X = randi(100,12,9,length(mins)); % Test matrix
以分钟为单位查找时间
[~,~,~,H,M] = datevec( mins );
H = 60 .* (H - H(1));
现在查找与我们的桶对应的所有时间
idxMIN = mod( M+H, NMINS )==0;
idxNewP = idxMIN; % This is used to align the new river matrix
[R,C,P] = size(X); % We'll drop P and use newP
newP = sum(idxNewP); % Number of PAGES in final matrix (new)
% Final newX will have dimensions [R,C,newP]
重置分组索引
% Must shift one all as minute intervals represent data UP to that point
% for the actual grouping of data. Test if first bucket is a
% match and set accordingly
if idxMIN(1)
idxMIN = [1; idxMIN(1:end-1)];
subs = cumsum(idxMIN);
else
idxMIN = [0; idxMIN(1:end-1)];
subs = cumsum(idxMIN) + 1 ;
end
加法:
团队规模不会一致,我不能(遗憾地)做出这样的假设。 运行考虑以上内容后考虑以下内容。
tsttbl = table();
tsttbl.dnumstr = datestr(mins(1:5));
tsttbl.Mins = M(1:5);
tsttbl.subs = subs(1:5);
tsttbl
输出显示第一组的大小为 1:
tsttbl =
dnumstr Mins subs
________ ____ ____
2:00 AM 0 1
2:05 AM 5 2
2:10 AM 10 2
2:15 AM 15 2
2:20 AM 20 3
最后,最终,我需要传递自定义函数。上面是一个玩具示例,可以快速说明问题。我很抱歉没有说得更清楚。
添加结束
这就是我绊倒的地方...
如何设置 subs 值以沿每个页面应用以使用 accumarray?我完全被文档弄糊涂了。或者这实际上是错误的方法?对于它的价值,我正在使用 Matlab 2015b。
老实说,我们将不胜感激。
替代解决方案
这在回家的路上打击了我。 Meshgrid 是我的朋友...
一旦上面的单元格已经 运行(注意我改变了矩阵 X 的大小),我们为整个矩阵创建索引,其中页面的 "indices"(即时间) 由 "subs" 中的值给出。为此,我使用了 meshgrid。
[days,rivers,pages] = meshgrid(1:C,1:R,subs);
grpvals = [rivers(:) days(:) pages(:)];
tst = accumarray(grpvals,X(:),[R C newP],@sum);
可能不是最有效的内存,因为我必须基本上创建天数、河流和页面矩阵,然后最终创建一个新的 grpvals 数组。但是,它的优点是现在我可以使用 accumarray 并传递匿名函数、@std 等。
希望这对其他人有帮助!
非常感谢路易斯。
如果所有组的大小都相同
您可以按如下方式进行聚合:
reshape
沿第 4 个维度构建要聚合的组。现在第 3 个维度指的是每个组的元素,第 4 个维度指的是组。
sum
沿第 3 个维度(每个组)。
squeeze
输出现在的单例第 3 维以恢复 3D 数组。
代码:
X = randi(9,2,3,6); %// example data. 3D array.
G = 2; %// group size along 3rd dim. Divides size(X,3)
result = squeeze(sum(reshape(X, size(X,1), size(X,2), G, []), 3));
例如 G = 2
,
X(:,:,1) =
2 3 9
4 5 9
X(:,:,2) =
3 8 2
6 9 8
X(:,:,3) =
4 4 4
1 1 7
X(:,:,4) =
9 9 8
2 4 1
X(:,:,5) =
9 5 9
3 5 8
X(:,:,6) =
9 1 3
5 3 1
给予
result(:,:,1) =
5 11 11
10 14 17
result(:,:,2) =
13 13 12
3 5 8
result(:,:,3) =
18 6 12
8 8 9
一般情况:大小可能不同的组
由于 accumarray
不适用于多维数组(甚至矩阵)作为第二个输入,您可以沿 行使用矩阵乘法。为此,您需要将 3D 数组的前两个维度打包成一维(最后将解包),并从组索引构建一个零一矩阵,该矩阵将通过矩阵乘法给出所需的结果。
X = randi(9,2,3,5); %// example data. 3D array.
subs = [1 2 2 1 1]; %// indices of groups. Groups may differ in size, and indices
%// need not be sorted
Y = reshape(X, [], size(X,3)); %// reshape into a matrix. Groups are along rows
M = full(sparse(1:numel(subs), subs, 1)); %// indicator matrix from group indices
result = reshape(Y*M, size(X,1), size(X,2), []); %// compute result and reshape
例如,
X(:,:,1) =
9 3 8
6 8 8
X(:,:,2) =
3 8 3
7 2 2
X(:,:,3) =
7 3 6
2 8 5
X(:,:,4) =
7 4 5
8 8 6
X(:,:,5) =
2 3 2
2 8 8
subs =
1 2 2 1 1
给予
result(:,:,1) =
18 10 15
16 24 22
result(:,:,2) =
10 11 9
9 10 7
我真的希望文档能更清楚地说明在 Matlab 中将 accumarray 用于 N 维大小矩阵。无论如何,我在这里完全困惑并寻求一些建议。这是挑战:
我有一个 3D 数据矩阵。
- ROWS 是个别河流
- 列是观察日期
- PAGES为数据采集的时间间隔
对于这个例子,我们假设每个观察值是在 5 分钟的时间间隔内流过仪表的水量。但是,我现在希望将数据重新采样为 N 分钟的间隔(显然是 5 的倍数)。让我们选择 NMINS = 15.
所以,我想做的是在 NMINS 分钟间隔内求出水量的总和或平均值。也就是说,ROWS 和 COLUMNS 不会改变,但 PAGES 的维度和值将是 decimated/aggregated.
我可以获得页面的分组值。也就是说,我需要分组的值。如果一天是一条河流,没问题。但是,我有几百天,几十条河。
我已经走到这一步了:
创建测试时间向量
NMINS = 15; % Bucket by every 15 mins or 20, etc.
N5MINS = 5 * 12 * 24 * 2; % Keep small - Two days of 5 min datenums
dnums = datenum(2016,3,20,0,0:5:N5MINS,0);
% Trim dnums to start at random time for edge case and keep only mins
mins = rem(dnums(25:end-30),1)'; % Create column vector
为测试创建随机矩阵
rng(123); % Set seed for reproducibility
X = randi(100,12,9,length(mins)); % Test matrix
以分钟为单位查找时间
[~,~,~,H,M] = datevec( mins );
H = 60 .* (H - H(1));
现在查找与我们的桶对应的所有时间
idxMIN = mod( M+H, NMINS )==0;
idxNewP = idxMIN; % This is used to align the new river matrix
[R,C,P] = size(X); % We'll drop P and use newP
newP = sum(idxNewP); % Number of PAGES in final matrix (new)
% Final newX will have dimensions [R,C,newP]
重置分组索引
% Must shift one all as minute intervals represent data UP to that point
% for the actual grouping of data. Test if first bucket is a
% match and set accordingly
if idxMIN(1)
idxMIN = [1; idxMIN(1:end-1)];
subs = cumsum(idxMIN);
else
idxMIN = [0; idxMIN(1:end-1)];
subs = cumsum(idxMIN) + 1 ;
end
加法: 团队规模不会一致,我不能(遗憾地)做出这样的假设。 运行考虑以上内容后考虑以下内容。
tsttbl = table();
tsttbl.dnumstr = datestr(mins(1:5));
tsttbl.Mins = M(1:5);
tsttbl.subs = subs(1:5);
tsttbl
输出显示第一组的大小为 1:
tsttbl =
dnumstr Mins subs
________ ____ ____
2:00 AM 0 1
2:05 AM 5 2
2:10 AM 10 2
2:15 AM 15 2
2:20 AM 20 3
最后,最终,我需要传递自定义函数。上面是一个玩具示例,可以快速说明问题。我很抱歉没有说得更清楚。
添加结束
这就是我绊倒的地方...
如何设置 subs 值以沿每个页面应用以使用 accumarray?我完全被文档弄糊涂了。或者这实际上是错误的方法?对于它的价值,我正在使用 Matlab 2015b。
老实说,我们将不胜感激。
替代解决方案 这在回家的路上打击了我。 Meshgrid 是我的朋友...
一旦上面的单元格已经 运行(注意我改变了矩阵 X 的大小),我们为整个矩阵创建索引,其中页面的 "indices"(即时间) 由 "subs" 中的值给出。为此,我使用了 meshgrid。
[days,rivers,pages] = meshgrid(1:C,1:R,subs);
grpvals = [rivers(:) days(:) pages(:)];
tst = accumarray(grpvals,X(:),[R C newP],@sum);
可能不是最有效的内存,因为我必须基本上创建天数、河流和页面矩阵,然后最终创建一个新的 grpvals 数组。但是,它的优点是现在我可以使用 accumarray 并传递匿名函数、@std 等。
希望这对其他人有帮助!
非常感谢路易斯。
如果所有组的大小都相同
您可以按如下方式进行聚合:
reshape
沿第 4 个维度构建要聚合的组。现在第 3 个维度指的是每个组的元素,第 4 个维度指的是组。sum
沿第 3 个维度(每个组)。squeeze
输出现在的单例第 3 维以恢复 3D 数组。
代码:
X = randi(9,2,3,6); %// example data. 3D array.
G = 2; %// group size along 3rd dim. Divides size(X,3)
result = squeeze(sum(reshape(X, size(X,1), size(X,2), G, []), 3));
例如 G = 2
,
X(:,:,1) =
2 3 9
4 5 9
X(:,:,2) =
3 8 2
6 9 8
X(:,:,3) =
4 4 4
1 1 7
X(:,:,4) =
9 9 8
2 4 1
X(:,:,5) =
9 5 9
3 5 8
X(:,:,6) =
9 1 3
5 3 1
给予
result(:,:,1) =
5 11 11
10 14 17
result(:,:,2) =
13 13 12
3 5 8
result(:,:,3) =
18 6 12
8 8 9
一般情况:大小可能不同的组
由于 accumarray
不适用于多维数组(甚至矩阵)作为第二个输入,您可以沿
X = randi(9,2,3,5); %// example data. 3D array.
subs = [1 2 2 1 1]; %// indices of groups. Groups may differ in size, and indices
%// need not be sorted
Y = reshape(X, [], size(X,3)); %// reshape into a matrix. Groups are along rows
M = full(sparse(1:numel(subs), subs, 1)); %// indicator matrix from group indices
result = reshape(Y*M, size(X,1), size(X,2), []); %// compute result and reshape
例如,
X(:,:,1) =
9 3 8
6 8 8
X(:,:,2) =
3 8 3
7 2 2
X(:,:,3) =
7 3 6
2 8 5
X(:,:,4) =
7 4 5
8 8 6
X(:,:,5) =
2 3 2
2 8 8
subs =
1 2 2 1 1
给予
result(:,:,1) =
18 10 15
16 24 22
result(:,:,2) =
10 11 9
9 10 7