【问题标题】:Vectorizing logic to check if index matches向量化逻辑以检查索引是否匹配
【发布时间】:2017-05-08 04:21:18
【问题描述】:

我有以下功能完美,但我想对其应用矢量化...

for i = 1:size(centroids,1)
    centroids(i, :) = mean(X(idx == i, :));
end

它检查idx 是否与当前索引匹配,如果匹配,它会计算与该索引对应的所有X 值的mean 值。

这是我对矢量化的尝试,我的解决方案不起作用,我知道为什么......

centroids = mean(X(idx == [1:size(centroids,1)], :));

以下idx == [1:size(centroids,1)] 破坏了代码。我不知道如何检查idx 是否等于1size(centroids,1) 之间的任何一个数字。

tl:dr

通过向量化摆脱for循环

【问题讨论】:

  • 你能举一个你的X向量的例子
  • 其实这里的for循环是多余的。 idx 的值将只等于 i 一次。你可以使用这条线来完成centroids(idx, :) = mean(X(idx, :));。但是,如果您想做一些不同的事情,顺便说一下,您的问题并不清楚,您应该提供X 值的示例和centroids 的所需输出

标签: matlab math octave vectorization


【解决方案1】:

一种选择是使用arrayfun

nIdx      = size(centroids,1);
centroids = arrayfun(@(ii) mean(X(idx==ii,:)),1:nIdx, 'UniformOutput', false);
centroids = vertcat(centroids{:})

由于单个函数调用的输出不一定是标量,因此必须将UniformOutput 选项设置为false。因此,arrayfun 返回一个元胞数组,您需要通过vertcat 获取所需的双精度数组。

【讨论】:

  • arrayfun 与显式循环具有或多或少相同的性能;它并不能真正算作矢量化
  • 嗯,arrayfun 是一个内置函数,即预编译。根据我的经验,它比显式循环提供更好的性能。
  • 视具体情况和matlab版本而定,但一般arrayfunis(或used为)slower
【解决方案2】:

您可以将矩阵拆分为单元格并使用cellfun(在其内部操作中应用循环)从每个单元格中取平均值:

生成数据:

dim = 10;
N = 400;
nc = 20;
idx = randi(nc,[N 1]);
X = rand(N,dim);
centroids = zeros(nc,dim);

意思是使用循环(问题的方法)

for i = 1:size(centroids,1)
    centroids(i, :) = mean(X(idx == i, :));
end

矢量化:

% split X into cells by idx
A = accumarray(idx, (1:N)', [nc,1], @(i) {X(i,:)});
% mean of each cell
C = cell2mat(cellfun(@(x) mean(x,1),A,'UniformOutput',0));

方法之间的最大绝对误差:

max(abs(C(:) - centroids(:))) % about 1e-16

【讨论】:

  • 抱歉,在我发布之前没有看到您的答案。为你投票,因为你是第一个回答的人。
  • 没关系,它们相似但不完全相同,所以最好有多种答案。
猜你喜欢
  • 1970-01-01
  • 2021-10-01
  • 1970-01-01
  • 2014-02-23
  • 2022-12-12
  • 1970-01-01
  • 1970-01-01
  • 2018-09-16
  • 1970-01-01
相关资源
最近更新 更多