【问题标题】:Return Unique Element with a Tolerance返回具有容差的唯一元素
【发布时间】:2010-01-01 13:00:10
【问题描述】:

在 Matlab 中,有一个 unique command,它返回数组中的唯一行。这是一个非常方便的命令。

但问题是我无法为其分配容差——在双精度中,我们总是必须在一个精度范围内比较两个元素。是否有内置命令在一定的容差范围内返回唯一元素?

【问题讨论】:

  • 让您的问题更进一步,也许您对集群感兴趣?

标签: matlab


【解决方案1】:

有了R2015a,这个问题终于有了一个简单的答案(详见my other answer to this question)。对于 R2015a 之前的版本,有这样一个内置(未记录的)函数:_mergesimpts。对名称组成的一个安全猜测是“合并相似点”。

使用以下语法调用该函数:

xMerged = builtin('_mergesimpts',x,tol,[type])

数据数组xN-by-D,其中N为点数,D为维数。每个尺寸的公差由D-元素行向量tol 指定。可选的输入参数type 是一个字符串('first'(默认)或'average'),指示如何合并相似的元素。

输出xMerged 将是M-by-D,其中M<=N已排序

示例,一维数据

>> x = [1; 1.1; 1.05];             % elements need not be sorted
>> builtin('_mergesimpts',x,eps)   % but the output is sorted
ans =
    1.0000
    1.0500
    1.1000

合并类型:

>> builtin('_mergesimpts',x,0.1,'first')
ans =
    1.0000  % first of [1, 1.05] since abs(1 - 1.05) < 0.1
    1.1000
>> builtin('_mergesimpts',x,0.1,'average')
ans =
    1.0250  % average of [1, 1.05]
    1.1000
>> builtin('_mergesimpts',x,0.2,'average')
ans =
    1.0500  % average of [1, 1.1, 1.05]

示例,2D 数据

>> x = [1 2; 1.06 2; 1.1 2; 1.1 2.03]
x =
    1.0000    2.0000
    1.0600    2.0000
    1.1000    2.0000
    1.1000    2.0300

机器精度特有的所有二维点:

>> xMerged = builtin('_mergesimpts',x,[eps eps],'first')
xMerged =
    1.0000    2.0000
    1.0600    2.0000
    1.1000    2.0000
    1.1000    2.0300

基于第二维公差合并:

>> xMerged = builtin('_mergesimpts',x,[eps 0.1],'first')
xMerged =
    1.0000    2.0000
    1.0600    2.0000
    1.1000    2.0000   % first of rows 3 and 4
>> xMerged = builtin('_mergesimpts',x,[eps 0.1],'average')
xMerged =
    1.0000    2.0000
    1.0600    2.0000
    1.1000    2.0150   % average of rows 3 and 4

基于第一维公差合并:

>> xMerged = builtin('_mergesimpts',x,[0.2 eps],'average')
xMerged =
    1.0533    2.0000   % average of rows 1 to 3
    1.1000    2.0300
>> xMerged = builtin('_mergesimpts',x,[0.05 eps],'average')
xMerged =
    1.0000    2.0000
    1.0800    2.0000   % average of rows 2 and 3
    1.1000    2.0300   % row 4 not merged because of second dimension

基于两个维度合并:

>> xMerged = builtin('_mergesimpts',x,[0.05 .1],'average')
xMerged =
    1.0000    2.0000
    1.0867    2.0100   % average of rows 2 to 4

【讨论】:

  • +1 不错!我自己遇到了这个功能,快速搜索让我得到了你的解释。这可能会派上用场。
  • @Amro 我在试图弄清楚griddata 如何识别“重复”点时发现了它。太糟糕了,这个功能没有适当的文档。请随时编辑这篇文章以纠正我的错误。我记得有一些不准确之处,或者至少缺少一些细节,但从来没有时间深入研究并确保 100% 正确。
  • 我想你已经涵盖了所有内容。我可以补充的唯一细节是该函数只接受非复杂非稀疏双精度数据点。
  • @chappjc 有没有办法获取 _mergesimpts 的代码?我制作了一个利用 _mergesimpts 的 matlab 函数。但是 matlab 代码生成器应用程序不能使用内置函数。有没有办法获取_mergesimpts的matlab代码?
  • @Abhinav 不。对不起。
【解决方案2】:

这是一个难题。我什至声称它一般是不可能解决的,因为我称之为传递性问题。假设我们在一个集合中有三个元素,{A,B,C}。我将定义一个简单的函数 isSimilarTo,这样如果两个输入在彼此指定的容差范围内,isSimilarTo(A,B) 将返回一个真结果。 (请注意,我将在这里说的所有内容在一维和多维中都有意义。)因此,如果已知两个数字彼此“相似”,那么我们将选择将它们组合在一起。

所以假设我们有值 {A,B,C} 使得 isSimilarTo(A,B) 为真,并且 isSimilarTo(B,C) 也为真。即使 isSimilarTo(A,C) 为假,我们是否应该决定将这三个组合在一起?

更糟糕的是,移动到二维。从围绕圆周等距分布的 k 个点开始。假设选择的容差使得任何点都在其直接邻居的指定容差范围内,但不在任何其他点的范围内。您将如何选择解决设置中哪些点是“独特的”?

我会声称这个不传递性问题使得分组问题无法解决,至少不能完美解决,当然也不能以任何有效的方式解决。也许有人可以尝试一种基于 k-means 聚合风格的方法。但这也会非常低效,而且这种方法通常需要提前知道要查找的组数。

话虽如此,我仍然会提出妥协,有时可以在一定范围内发挥作用。该技巧可在 Consolidator 中找到,可在 Matlab Central 文件交换中找到。我的方法是有效地将输入四舍五入到指定的容差范围内。完成此操作后,unique 和 accumarray 的组合可以有效地完成聚合,即使对于一维或多维的大型数据集也是如此。

当容差足够大时,这是一种合理的方法,当多条数据属于一起时,它们将被舍入到相同的值,舍入步骤偶尔会出现错误。

【讨论】:

    【解决方案3】:

    从 R2015a 开始,终于有一个函数可以做到这一点,uniquetol在 R2015a 之前,见 my other answer):

    uniquetol 在容差范围内设置唯一性。

    uniquetol 类似于 uniqueunique 执行精确比较,uniquetol 使用容差执行比较。

    语法很简单:

    C = uniquetol(A,TOL) 使用容差TOL 返回A 中的唯一值。

    语义也是如此:

    C 的每个值都在A 的一个值的容差范围内,但C 中没有两个元素彼此处于容差范围内。 C 按升序排列。两个值 uv 在公差范围内,如果:
    abs(u-v) &lt;= TOL*max(A(:),[],1)

    它还可以操作“ByRows”,并且可以通过输入“DataScale”而不是输入数据中的最大值来缩放容差。

    但是关于解决方案的独特性有一个重要说明:

    可以有多个满足条件的有效C 输出,“C 中没有两个元素在彼此的容差范围内。”例如,交换A 中的列可能会导致返回不同的解决方案,因为输入按列按字典顺序排序。另一个结果是uniquetol(-A,TOL) 可能不会给出与-uniquetol(A,TOL) 相同的结果。

    还有一个新函数ismembertolismember相关,方法同上。

    【讨论】:

      【解决方案4】:

      据我所知,没有这样的功能。一个棘手的方面是,如果您的容差是 1e-10,并且您有一个向量的值在 9e-11 处等距,则第一个和第三个条目不一样,但第一个条目与第二个,第二个和第三个一样——那么有多少个“独特”呢?

      解决问题的一种方法是将值四舍五入到所需的精度,然后在该精度上运行唯一值。您可以使用 round2 (http://www.mathworks.com/matlabcentral/fileexchange/4261-round2) 或使用以下简单方法:

      r = rand(100,1); % some random data
      roundedData = round(r*1e6)/1e6; % round to 1e-6
      uniqueValues = unique(roundedData);
      

      你也可以使用 hist 命令,只要精度不太高:

      r = rand(100,1); % create 100 random values between 0 and 1
      grid = 0:0.001:1; % creates a vector of uniquely spaced values 
      counts = hist(r,grid); % now you know for each element in 'grid' how many values there are
      uniqueValues = grid(counts>0); % and these are the uniques
      

      【讨论】:

        【解决方案5】:

        我以前遇到过这个问题。诀窍是首先对数据进行排序,然后使用 diff 函数找出每个项目之间的差异。然后比较该差异何时小于您的容忍度。 这是我使用的代码:

        tol = 0.001
        [Y I] = sort(items(:));
        uni_mask = diff([0; Y]) > tol;
        %if you just want the unique items:
        uni_items = Y(uni_mask); %in sorted order
        uni_items = items(I(uni_mask));  % in the original order
        

        这不考虑“漂移”......所以像 0:0.00001:100 这样的东西实际上会返回一个唯一值。

        如果你想要一些可以处理“漂移”的东西,那么我会使用 histc 但你需要对你愿意拥有多少物品做出某种粗略的猜测。

        NUM = round(numel(items) / 10); % a rough guess
        bins = linspace(min(items), max(items), NUM);
        counts = histc(items, bins);
        unit_items = bins(counts > 0);
        

        顺便说一句:我是在远离 matlab 的文本编辑器中编写的,因此可能存在一些愚蠢的拼写错误或一个错误。

        希望有帮助

        【讨论】:

          【解决方案6】:

          这很难很好地定义,假设您的容差为 1。 那么[1; 2; 3; 4] 的结果是什么?

          当您有多个列时,定义可能会变得更具挑战性。

          但是,如果您最担心的是舍入问题,您可以通过以下两种方法之一解决大部分问题:

          1. 将所有数字四舍五入(考虑到您的容差),然后使用unique
          2. 从第一行作为您的唯一集开始,使用ismemberf 确定每个新行是否唯一,如果是,将其添加到您的唯一集。

          第一种方法的缺点是 0.499999999 和 0.500000000 可能不会被视为重复项。而第二种方法的弱点是输入的顺序很重要。

          【讨论】:

            【解决方案7】:

            前几天我被 MatLab 2010 卡住了,所以,没有 round(X,n),没有 _mergesimpts(至少我无法让它工作)所以,一个简单的解决方案有效(至少对我的数据而言):

            使用rat默认容差:

            unique(cellstr(rat(x)))
            

            其他公差:

            unique(cellstr(rat(x,tol)))
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-03-27
              • 1970-01-01
              • 2018-12-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多