Matlab 如何删除双数组中的重复行,以便没有一行与其前一行相同

Matlab 如何删除双数组中的重复行,以便没有一行与其前一行相同,matlab,Matlab,我有4个n×1的列向量,其中共享相同的索引号意味着它们具有相同的时间戳。我想删除与前面的“行”相同的“行”,并设想递归地执行此操作,直到没有更改为止 例如,假设这4个向量是 C1=[1;1;3;3;1;1]; C2=[2;2;4;4;2;2]; C3=[0;0;0;0;0;0]; C4=[5;5;6;6;5;5]; 所需输出为 ans=[1;3;5]; 因为[C1(ans)、C2(ans)、C3(ans)、C4(ans)]是一个数组,没有与其前一行相同的行。在上述示例中,生成的向量如下所示:

我有4个n×1的列向量,其中共享相同的索引号意味着它们具有相同的时间戳。我想删除与前面的“行”相同的“行”,并设想递归地执行此操作,直到没有更改为止

例如,假设这4个向量是

C1=[1;1;3;3;1;1];
C2=[2;2;4;4;2;2];
C3=[0;0;0;0;0;0];
C4=[5;5;6;6;5;5];
所需输出为

ans=[1;3;5];
因为
[C1(ans)、C2(ans)、C3(ans)、C4(ans)]
是一个数组,没有与其前一行相同的行。在上述示例中,生成的向量如下所示:

C1=[1;3;1];
C2=[2;4;2];
C3=[0;0;0];
C4=[5;6;5];
“行”是指当查看与
[C1、C2、C3、C4]
按列连接的向量时的行

问题是:
  • 我知道如何做它与循环。如何使用本机Matlab函数实现这一点

一些注释

我从4个分离的列向量开始的原因如下:

  • 我还有一个n×1的向量,其中包含唯一元素,我将根据为其他4个向量移除的索引移除相同的“行”

  • 在我的应用程序中,数据是从别处检索的,并逐元素存储到Maltab数据类型中进行进一步处理,我遇到了性能优势,将数据存储到4n-by-1 double中,再存储到1n-by-4 double中。这个N是几十万或者几百万

  • n通常一次只有几千个,但我需要将每次过滤所需的时间尽可能减少到1秒以内

    (我想学习使用本机函数的方法并比较性能。)


    关于业绩的说明 由于随机数据不合适,过于具体的数据也不合适,所以在这一点上演示性能差异有点困难。(我所说的“难”是指很难快速完成。)

    但是,如果有人感兴趣的话,
    timeit()
    的结果如下:表中有约164k行,但只有约1k行是“唯一”行(“”)

    • Cris'
      diff或
      方法:0.0028s

    • Wolfie的
      独特
      方法:0.0142s

    • Wolfie's
      arrayfun
      方法:0.3912s

    • Thomas's
      diff*ones
      方法:0.0057s

    • Thomas的递归方法:无法完成。这在
      timeit()
      下执行一分钟后,将Matlab的RAM请求放大到~70GB,并导致Win 10机器上的UI冻结,尽管该机器有大量未使用的CPU

    • 循环(但在列数上使用
      varargin
      ):3.6313s

    测试函数包括连接(如果不是直接处理列的话)

    循环版本为:

    function varargout = accum(varargin)
    
        for i=1:numel(varargin)
            varargout{i}=varargin{i}(1);    % assuming single column
        end
    
        for i=2:numel(varargin{1})  % assuming equal length
            TF=false;
            for j=1:numel(varargin)
                TF=TF||varargin{j}(i)~=varargin{j}(i-1);
            end
            if TF
                for j=1:numel(varargin)
                    varargout{j}=[varargout{j};varargin{j}(i)];
                end
            end
        end
    
    end
    

    如果你正在写另一个答案,需要样本数据,请告诉我。否则,我将跳过粘贴它,因为这样做没有什么用处。

    这里有一个选项,使用逻辑值将矩阵中的行子集

    C([true; abs(C(2:end,:)-C(1:end-1,:))*ones(size(C,2),1)>0],:)
    

    ans =
    
       1   2   0   5
       3   4   0   6
       1   2   0   5
    

    如果您不介意使用用户函数方法,下面可能是另一个选项,
    myfun
    递归计算“唯一”行

    以致

    >> z = myfun(C)
    z =
    
       1   2   0   5
       3   4   0   6
       1   2   0   5
    
    

    其中
    C=[C1、C2、C3、C4]
    我认为以下给出了所需的输出(未测试):

    find([1;diff(C1)| diff(C2)| diff(C3)| diff(C4)])
    

    diff
    为非零,其中两个后续元素不同。使用逻辑OR,我们要求任何一个向量在任何一个位置都有差异。第一个元素始终是输出的一部分
    find
    返回非零元素的索引。

    您可以使用与Cris给出的答案类似的方法(
    find(diff(…))
    ),但使用
    unique
    使其更通用

    设置:

    C1=[1;1;3;3;1;1];
    C2=[2;2;4;4;2;2];
    C3=[0;0;0;0;0;0];
    C4=[5;5;6;6;5;5];
    
    C = [C1,C2,C3,C4];
    
    [~,~,iu] = unique( C, 'rows' );
    idx = find( [1; diff(iu)] );
    
    idx = find( [1, arrayfun( @(ii) any(C(ii,:) ~= C(ii-1,:)), 2:size(C,1) )] )
    
    方法一:

    C1=[1;1;3;3;1;1];
    C2=[2;2;4;4;2;2];
    C3=[0;0;0;0;0;0];
    C4=[5;5;6;6;5;5];
    
    C = [C1,C2,C3,C4];
    
    [~,~,iu] = unique( C, 'rows' );
    idx = find( [1; diff(iu)] );
    
    idx = find( [1, arrayfun( @(ii) any(C(ii,:) ~= C(ii-1,:)), 2:size(C,1) )] )
    
    或者,您可以循环(简写为
    arrayfun
    )查找任何元素与前一行不同的行

    方法二:

    C1=[1;1;3;3;1;1];
    C2=[2;2;4;4;2;2];
    C3=[0;0;0;0;0;0];
    C4=[5;5;6;6;5;5];
    
    C = [C1,C2,C3,C4];
    
    [~,~,iu] = unique( C, 'rows' );
    idx = find( [1; diff(iu)] );
    
    idx = find( [1, arrayfun( @(ii) any(C(ii,:) ~= C(ii-1,:)), 2:size(C,1) )] )
    

    谢谢你的回答。但是
    unique(u,'rows')
    不应该工作,因为示例中的第一个和第三个元素可能相同,因为可能存在中间不同的“rows”。我将编辑示例以显示它。@Argyll感谢您的反馈。我通过定义一个用户函数更新了我的答案。希望它有意义代码有意义。谢谢你的解决方案。在得到更多答案后,我将在稍后发布一条注释,以重新进行基准测试。@Argyll我想如果您有许多行,那么用户函数可能会很慢。我添加了另一种应该更快的方法。只是一个问题,我想你对原始数据没有控制权?因为在这种情况下,可以将数据推送到应用程序的实时数据库(firebase、RejectionDB,…)可以大大减少所需的计算量。@obchardon:Ya我无法控制数据源。到时候,我将使用不同的供应商。但我目前的资料在某种程度上是有效的,而且价格低廉。因此,为了让一些工作顺利进行,我需要使用当前的供应商,并且在任何情况下,供应商都以独特的方式提供有价值的东西——便宜。