【问题标题】:How to compare two unsorted lists in Matlab?如何比较 Matlab 中的两个未排序列表?
【发布时间】:2014-11-29 18:51:42
【问题描述】:

我有两个二维点列表,分别为 M x 2 - 和 N x 2 - 矩阵,其中 M 和 N 可能非常大。

确定其中有多少相等的最快方法是什么?

【问题讨论】:

  • size(intersect(v1,v2,'rows'),1) 呢?

标签: matlab


【解决方案1】:

我不确定您是否要计算重复条目,但如果不是,您可以使用intersect 或一些基于排序的非常直观的算法(见下文)。我不喜欢嵌套循环版本...

function test_compareVecs()
    %% create some random data
    N = 31415;
    M1 = 100000;
    M2 = 200000;
    vec = rand(N,2);
    v1 = [rand(M1-N,2); vec];
    v2 = [rand(M2-N,2); vec];
    v1 = v1(randperm(M1),:);
    v2 = v2(randperm(M2),:);

    %% intersect
    disp('intersect:');
    tic
    s = size(intersect(v1,v2,'rows'),1);
    toc;
    s

    %% alternative approach
    disp('alternative approach:');
    tic;
    s = compareVecs(v1,v2);
    toc;
    s    
end

function s = compareVecs(v1,v2)
    %% create help vector
    help_vec = [[v1,zeros(size(v1,1),1)]; ...
                [v2,ones(size(v2,1),1)]]; 

    %% sort by first column
    % note: for some reason "sortrows(help_vec,1)" is slower
    hash_vec = help_vec(:,1); % dummy hash
    [~,sidx] = sort(hash_vec);
    help_vec = help_vec(sidx,:);

    %% diff + compare
    help_vec = diff(help_vec);    
    s = sum(help_vec(:,1) == 0 & ...
            help_vec(:,2) == 0 & ...
            help_vec(:,3) ~= 0);
end

结果

intersect:
Elapsed time is 0.145717 seconds.
s = 31415

alternative approach:
Elapsed time is 0.048084 seconds.
s = 31415

【讨论】:

    【解决方案2】:

    使用pdist2 计算所有成对距离,然后计算距离为零的对。如果坐标是浮点值,您可能希望使用容差而不是与零进行比较:

    %// Data:
    M = 10;
    N = 8;
    listM = randi(10,M,2)-1;
    listN = randi(10,N,2)-1;
    tol = 1e-6;
    %// Distance matrix:
    d = pdist2(listM, listN);
    %// Count:
    count = sum(d(:)<tol);
    

    【讨论】:

    • 很抱歉,但这并不是很有说服力。它甚至比嵌套循环更糟糕,因为它不仅在计算时间上是 O(n²),而且在内存上也是如此!您是否使用这种方法尝试过我的数据?紧凑的代码并不总是最好的答案...
    • 我同意这是紧凑的,但内存效率不高。根据 OP 使用的 MN,它可能是一个很好的解决方案
    • 如果您想要一个紧凑的解决方案,intersect one-liner 是更好的选择 :)
    • @matheburg 好想!我没有在您的解决方案中看到这一点
    【解决方案3】:

    无论每个列表中点的顺序或长度如何,这都应该有效。它是一种哈希表/字典解决方案,应该很快,但内存需求与列表的长度成线性关系。请注意,下面的语法可能并不完美,但快速参考提到的主要数据结构应该可以轻松进行更正。

    (1) 填充一个类似字典的containers.Map,其中键是点的唯一函数,例如num2str(M(i,1))'-'num2str(M(i,2)).

    (2) 然后,遍历第二个列表的所有元素,像 (1) 中一样创建键并检查它是否存在。如果是,则设置map(key)=1,否则设置为0。最后,所有由公共点组成的键都将存储1,其余的将为零。

    (3) 通过对地图的值求和(类似于sum(map.values()))来完成,这应该为您提供两组之间唯一交叉点的总数,而不管这些点的顺序如何出现在每个列表中。

    OBS:如果您不想只计算唯一的交叉点而是所有重复点,请在 (2) 中,而不是创建 map(key)=1,将 1 添加到 map(key)。其余的都是一样的。

    【讨论】:

    • 嗯...这听起来像是嵌套循环的错误版本。您不应该在比较之前至少对列表进行排序以将整体复杂性降低到 O(nlog(n)) 吗?否则你的字典对我没有意义。即使你对它进行排序,这正是我正在以更有效的方式做的事情。我错了吗?请提供代码以证明您的适用性和评估;我确定我这里出了点问题......
    猜你喜欢
    • 2015-07-19
    • 2019-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多