7

我有相当大的阵列。为了简单起见,让我们将其简化为:

A = [1 1 1 1 2 2 3 3 3 3 4 4 5 5 5 5 5 5 5 5];

因此,有一组 1(4 个元素)、2's(2 个元素)、3's(4 个元素)、4's(2 个元素)和 5's(8 个元素)。现在,我只想保留属于 3 个或更多元素组的列。所以它会像:

B = [1 1 1 1 3 3 3 3 5 5 5 5 5 5 5 5];

我正在使用for循环执行此操作,分别扫描 1、2、3 等等,但是对于大数组来说它非常慢……感谢您提出如何以更有效的方式进行操作的任何建议 :) 艺术。

4

4 回答 4

8

一般方法

如果您的向量不一定是排序的,那么您需要运行以计算向量中每个元素的出现次数。你histc只需要:

elem = unique(A);
counts = histc(A, elem);
B = A;
B(ismember(A, elem(counts < 3))) = []

最后一行选择出现次数少于 3 次的元素并将其删除。

分组向量的一种方法

如果您的向量是“半排序的”,也就是说,如果向量中的相似元素被分组在一起(如您的示例中所示),您可以通过执行以下操作来加快速度:

start_idx = find(diff([0, A]))
counts = diff([start_idx, numel(A) + 1]);
B = A;
B(ismember(A, A(start_idx(counts < 3)))) = []

再次注意,向量不需要完全排序,只要相似的元素彼此相邻即可。

于 2012-09-20T11:54:26.730 回答
7

这是我的两个班轮

counts = accumarray(A', 1);
B = A(ismember(A, find(counts>=3)));

accumarray 用于计算 A 的各个成员。 find 提取符合“3 个或更多元素”标准的成员。最后,ismember 会告诉您它们在 A 中的位置。请注意,A 不需要排序。当然, accumarray 仅适用于 A 中的整数值。

于 2012-09-20T12:15:04.973 回答
3

您所描述的称为运行长度编码

在 FileExchange 上的 Matlab 中有用于此的软件。或者你可以直接这样做:

len = diff([ 0 find(A(1:end-1) ~= A(2:end)) length(A) ]);
val = A(logical([ A(1:end-1) ~= A(2:end) 1 ]));

一旦你有了游程编码,你就可以根据长度删除元素。IE

idx = (len>=3)
len = len(idx);
val = val(idx);

然后解码得到你想要的数组:

i = cumsum(len);
j = zeros(1, i(end));
j(i(1:end-1)+1) = 1; 
j(1) = 1; 
B = val(cumsum(j));
于 2012-09-20T11:21:07.197 回答
1

这是使用 matlab 内置函数的另一种方法。

% Set up
A=[1 1 1 1 2 2 3 3 3 3 4 4 5 5 5 5 5];
threshold=2;

% Get the unique elements of the array
uniqueElements=unique(A);

% Count haw many times each unique element occurs
counts=histc(A,uniqueElements);

% Write which elements should be kept
toKeep=uniqueElements(counts>threshold);

% Make a logical index
indexer=false(size(A));
for i=1:length(toKeep)
    % For every unique element we want to keep select the indices in A that
    % are equal
    indexer=indexer|(toKeep(i)==A);
end

% Apply index
B=A(indexer);
于 2012-09-20T11:28:51.930 回答