Poe*_*lie 2 optimization matlab vector vectorization mean
我有两个向量
data vector: A = [1 2 2 1 2 6; 2 3 2 3 3 5]
label vector: B = [1 2 1 2 3 NaN]
Run Code Online (Sandbox Code Playgroud)
我想取所有具有相同标签的列的平均值,并将它们输出为按标签号排序的矩阵,忽略NaN.所以,在这个例子中我想要:
labelmean(A,B) = [1.5 1.5 2; 2 3 3]
Run Code Online (Sandbox Code Playgroud)
这可以通过像这样的for循环来完成.
function out = labelmean(data,label)
out=[];
for i=unique(label)
if isnan(i); continue; end
out = [out, mean(data(:,label==i),2)];
end
Run Code Online (Sandbox Code Playgroud)
但是,我正在处理包含许多数据点和标签的巨大数组.此外,此代码段将经常执行.我想知道是否有更有效的方法来做到这一点,而不是遍历每个单独的标签.
这将是一个很好的使用案例accumarray
.可以将其accumarray
视为一种微型MapReduce范例.有键和值,所以工作accumarray
是将所有共享相同键的值组合在一起,并对这些值执行某些操作.在您的情况下,键将是元素,B
但值将是相应值所需的行位置B
.基本上,对于每个值B
,位置B
告诉您需要访问哪一行A
.因此,我们只需要获取映射到相同ID的所有行位置,访问行A
,然后查找所有行的平均值.我们需要小心,因为我们忽略了它们的价值NaN
.我们可以在打电话之前过滤掉这些accumarray
.accumarray
传统上你做的"东西" 应该输出一个数字,但实际上我们为每个标签输出一个列向量.因此,一个技巧是将输出包装到单元格数组中,然后cat
结合使用逗号分隔列表将输出转换为矩阵.
因此,这样的事情应该有效:
% Sample data
A = [1 2 2 1 2 6; 2 3 2 3 3 5];
B = [1 2 1 2 3 NaN];
% Find non-NaN locations
mask = ~isnan(B);
% Generate row locations that are not NaN as well as the labels
ind = 1 : numel(B);
Bf = B(mask).';
ind = ind(mask).';
% Find label-wise means
C = accumarray(Bf, ind, [], @(x) {mean(A(:,x), 2)});
% Convert to numeric matrix
out = cat(2, C{:});
Run Code Online (Sandbox Code Playgroud)
如果您不喜欢使用临时变量来查找这些非NaN
值,我们可以使用较少的代码行来完成此操作,但您仍需要行索引向量来确定我们需要从哪里进行采样:
% Sample data
A = [1 2 2 1 2 6; 2 3 2 3 3 5];
B = [1 2 1 2 3 NaN];
% Solution
ind = 1 : numel(B);
C = accumarray(B(~isnan(B)).', ind(~isnan(B)).', [], @(x) {mean(A(:,x), 2)});
out = cat(2, C{:});
Run Code Online (Sandbox Code Playgroud)
根据您的数据,我们得到:
>> out
out =
1.5000 1.5000 2.0000
2.0000 3.0000 3.0000
Run Code Online (Sandbox Code Playgroud)
这是一种方法:
NaN
s 的标签索引.A
将得到所需行总和的稀疏矩阵.码:
I = find(~isnan(B)); % step 1
t = sparse(I, B(I), 1, size(A,2), max(B(I))); % step 2
t = bsxfun(@rdivide, t, sum(t,1)); % step 3
result = full(A*t); % step 4
Run Code Online (Sandbox Code Playgroud)