我试图找到一种最快的方法来找到数组中的唯一值,并删除0作为唯一值的可能性。
现在我有两个解决方案:
result1 = setxor(0, dataArray(1:end,1)); % This gives the correct solution
result2 = unique(dataArray(1:end,1)); % This solution is faster but doesn't give the same result as result1dataArray相当于:
dataArray = [0 0; 0 2; 0 4; 0 6; 1 0; 1 2; 1 4; 1 6; 2 0; 2 2; 2 4; 2 6]; % This is a small array, but in my case there are usually over 10 000 lines.所以在这种情况下,result1等于[1; 2],result2等于[0; 1; 2]。unique函数速度更快,但我不希望考虑0。是否有一种方法可以用unique来实现这一点,而不是将0视为一个独特的值?还有别的选择吗?
编辑
我想给出不同的解决方案。
clc
dataArray = floor(10*rand(10e3,10));
dataArray(mod(dataArray(:,1),3)==0)=0;
% Initial
tic
for ii = 1:10000
FCT1 = setxor(0, dataArray(:,1));
end
toc
% My solution
tic
for ii = 1:10000
FCT2 = unique(dataArray(dataArray(:,1)>0,1));
end
toc
% Pursuit solution
tic
for ii = 1:10000
FCT3 = unique(dataArray(:, 1));
FCT3(FCT3==0) = [];
end
toc
% Pursuit solution with chappjc comment
tic
for ii = 1:10000
FCT32 = unique(dataArray(:, 1));
FCT32 = FCT32(FCT32~=0);
end
toc
% chappjc solution
tic
for ii = 1:10000
FCT4 = setdiff(unique(dataArray(:,1)),0);
end
toc
% chappjc 2nd solution
tic
for ii = 1:10000
FCT5 = find(accumarray(dataArray(:,1)+1,1))-1;
FCT5 = FCT5(FCT5>0);
end
toc其结果是:
Elapsed time is 5.153571 seconds. % FCT1 Initial
Elapsed time is 3.837637 seconds. % FCT2 My solution
Elapsed time is 3.464652 seconds. % FCT3 Pursuit solution
Elapsed time is 3.414338 seconds. % FCT32 Pursuit solution with chappjc comment
Elapsed time is 4.097164 seconds. % FCT4 chappjc solution
Elapsed time is 0.936623 seconds. % FCT5 chappjc 2nd solution但是,sparse和accumarray的解决方案只适用于integer。这些解决方案不适用于double。
发布于 2013-12-18 20:36:13
下面是一个关于accumarray的古怪建议,用Floris的测试数据演示:
a = floor(10*rand(100000, 1)); a(mod(a,3)==0)=0;
result = find(accumarray(nonzeros(a(:,1))+1,1))-1;感谢Luis指出使用nonzeros,不需要执行result = result(result>0)!
请注意,此解决方案需要整数值数据(不一定是整数数据类型,只是不需要使用十进制组件)。像unique那样,比较浮点值是否相等是很危险的。见这里和这里。
最初的建议:将unique与setdiff相结合
result = setdiff(unique(a(:,1)),0)或在unique之后使用逻辑索引删除
result = unique(a(:,1));
result = result(result>0);我通常不喜欢像在( [] )中那样分配result(result==0)=[];,因为对于大型数据集,它变得非常低效。
在unique之后移除零应该更快,因为它对较少的数据进行操作(除非每个元素都是唯一的,或者如果a/dataArray非常短的话)。
发布于 2013-12-18 20:51:55
只是为了增加一般的喧嚣-这里有三种不同的方法。他们都给出了相同的答案,但时间略有不同:
a = floor(10*rand(100000, 1));
a(mod(a,3)==0)=0;
tic
b1 = unique(a(:,1));
b1(b1==0) = [];
toc
tic
b2 = find(sparse(a(:,1)+1, 1, 1)) - 1;
b2(b2==0)=[];
toc
tic
b3 = setxor(0, a(:, 1), 'rows');
toc
display(b1)
display(b2)
display(b3)在我的机器上,时间(用于100000个元素的数组)如下所示:
0.0087 s - for unique
0.0142 s - for find(sparse)
0.0302 s = for setxor对于这样的问题,我总是喜欢sparse --您可以同时得到元素的计数和它们的唯一值。
编辑 per @chappj的建议。我增加了第四种选择
b4 = find(accumarray(a(:,1)+1,1)-1);
b4(b4==0) = [];时间:
0.0029 s , THREE TIMES FASTER THAN UNIQUE女士们先生们,我们有赢家了。
,,基于索引的方法(sparse和accumarray)只处理整数值输入(尽管它们可以是double类型)。根据问题中给出的输入数组,这似乎是可以的,但对于非整数值的输入则不起作用。当然,当你有双数时,unique是一个棘手的概念--“看起来”相同的数字可能以不同的方式表示。您可以考虑截断输入数组(清理数据)以确保这不是问题。例如,如果你做了
a = 0.001 * double(int(a * 1000));您可以将所有值舍入到不超过3个重要数字,并且因为您“通过一个int”,所以您肯定不会得到“非常微妙的不同”的值(例如8位数或更高的值)。当然,在这种情况下,你也可以
a = round(a * 1000);
mina = min(a(:));
b = find(accumarray(a - mina + 1, 1)) + mina - 1;
b = 0.001 * b(b ~= 0);对于非整数值来说,这是“相当健壮的”(在上面的情况下,它处理的值高达三个有效位数;如果需要更多的数据,空间需求最终会变得太大,而且这种方法将比unique慢,后者实际上必须对数据进行排序)。
发布于 2013-12-18 20:35:37
作为第二步,为什么不移除零:
result2 = unique(.....);
result2 = (result2~=0);https://stackoverflow.com/questions/20667745
复制相似问题