如何在不使用 MATLAB 循环的情况下查找向量中元素子集的出现次数?
How to find number of occurrences of a subset of elements in a vector without using loops in MATLAB?
假设 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
,但我想不出在这种情况下如何使用它们来获得所需的输出。
快速选择
您可以使用 bsxfun
结合 sum
来计算这个
sum(bsxfun(@eq, Y, X.'), 2)
说明
在此示例中,bsxfun
对 X
和 Y
中的每个元素组合执行给定操作。我们要使用的操作是 eq
(检查是否相等)。结果是一个矩阵,其中 Y
中的每个元素对应一行,X
中的每个元素对应一列。如果 X
中的元素等于 Y
中对应于给定行的元素,它将具有 1
值。
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
我们可以使用第二个输入来 "group" 将相同的值放在一起。 accumarray
函数正是这样做的,它使用上面的 ind
变量来确定组,然后将给定的操作应用于每个组。在我们的例子中,我们只想确定每个组中元素的数量。所以要做到这一点,我们可以传递第二个输入,大小为 ind
输入(减去不匹配的),然后使用 numel
作为操作(计算每个中的数字)组)
counts = accumarray(ind(tf), ones(sum(tf), 1), [numel(Y), 1], @numel);
% 1
% 3
% 2
假设 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
,但我想不出在这种情况下如何使用它们来获得所需的输出。
快速选择
您可以使用 bsxfun
结合 sum
来计算这个
sum(bsxfun(@eq, Y, X.'), 2)
说明
在此示例中,bsxfun
对 X
和 Y
中的每个元素组合执行给定操作。我们要使用的操作是 eq
(检查是否相等)。结果是一个矩阵,其中 Y
中的每个元素对应一行,X
中的每个元素对应一列。如果 X
中的元素等于 Y
中对应于给定行的元素,它将具有 1
值。
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
我们可以使用第二个输入来 "group" 将相同的值放在一起。 accumarray
函数正是这样做的,它使用上面的 ind
变量来确定组,然后将给定的操作应用于每个组。在我们的例子中,我们只想确定每个组中元素的数量。所以要做到这一点,我们可以传递第二个输入,大小为 ind
输入(减去不匹配的),然后使用 numel
作为操作(计算每个中的数字)组)
counts = accumarray(ind(tf), ones(sum(tf), 1), [numel(Y), 1], @numel);
% 1
% 3
% 2