说X是给定的向量:
X=[1
2
4
2
3
1
4
5
2
4
5];
Y是X中给定元素的子集:
Y=[3
4
5];
所需输出是Y中元素出现在X中的次数:
out=[1
3
2];
我这样做的解决方案是使用for
循环:
for i=1:size(X,1)
temp = X(X(:,1)==Y(i,1),:);
out(i,1) = size(temp,1);
end
但是当X和Y很大时,效率很低。那么,如何更快地利用矢量化呢?我知道hist
和histc
,但我无法想到如何在这种情况下使用它们来获得所需的输出。
答案 0 :(得分:5)
您可以使用bsxfun
与sum
相结合来计算此
sum(bsxfun(@eq, Y, X.'), 2)
<强>解释强>
在此示例中,bsxfun
对X
和Y
中的每个元素组合执行给定操作。我们要使用的操作是eq
(检查相等性)。结果是一个矩阵,Y
中的每个元素都有一行,X
中的每个元素都有一列。如果1
中的元素等于X
中与给定行对应的元素,则它将具有Y
值。
bsxfun(@eq, Y, X.')
% 0 0 0 0 1 0 0 0 0 0 0
% 0 0 1 0 0 0 1 0 0 1 0
% 0 0 0 0 0 0 0 1 0 0 1
然后,我们可以对列进行求和,以计算X
中与Y
中的给定值相等的元素数。
sum(bsxfun(@eq, Y, X.'), 2)
% 1
% 3
% 2
在较新版本的MATLAB上(自R2016b起),您可以省略bsxfun
,因为相等操作将自动广播。
sum(Y - X.', 2)
第一个选项效率不高,因为它需要创建一个[numel(Y), numel(X)]
元素大的矩阵。另一种可能更高效记忆的方法可能是使用ismember
的第二项输出结合accumarray
[tf, ind] = ismember(X, Y);
counts = accumarray(ind(tf), ones(sum(tf), 1), [numel(Y), 1], @numel);
<强>解释强>
ismember
用于确定一个数组中的值是否在另一个数组中。第一个输入告诉我们 if 第一个输入的每个元素是否在第二个输入中,第二个输出告诉你第二个输入中的 where 第一个输入的每个元素都被找到
[tf, ind] = ismember(X, Y);
% 0 0 1 0 1 0 1 1 0 1 1
% 0 0 2 0 1 0 2 3 0 2 3
我们可以使用第二个输入将相同的值“分组”在一起。 accumarray
函数就是这样做的,它使用上面的ind
变量来确定组,然后将给定的操作应用于每个组。在我们的例子中,我们想要简单地确定每个组中的元素数量。所以要做到这一点,我们可以传递第二个输入,其大小为ind
输入(减去那些不匹配的输入),然后使用numel
作为操作(计算每个输入中的数字)基)
counts = accumarray(ind(tf), ones(sum(tf), 1), [numel(Y), 1], @numel);
% 1
% 3
% 2