返回带有容差的唯一元素

Gra*_*ton 17 matlab

在Matlab中,有一个unique命令可以返回数组中的唯一行.这是一个非常方便的命令.

但问题在于我不能为它赋予容差 - 在双精度中,我们总是需要比较精度内的两个元素.是否有内置命令在特定容差范围内返回唯一元素?

cha*_*pjc 13

使用R2015a,这个问题最终得到了一个简单的答案(详情请参阅我对这个问题的其他答案).对于R2015a之前的版本,有一个内置的(未记录的)功能:_mergesimpts.对名称组成的安全猜测是"合并相似点".

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

xMerged = builtin('_mergesimpts',x,tol,[type])
Run Code Online (Sandbox Code Playgroud)

数据数组x是点数N-by-D,其中ND维数.每个维度的容差由D-element行向量指定tol.可选的输入参数type是一个字符串('first'(默认)或'average'),指示如何合并类似的元素.

输出xMerged将在M-by-D哪里M<=N.它已分类.

例子,1D数据:

>> 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
Run Code Online (Sandbox Code Playgroud)

合并类型:

>> 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]
Run Code Online (Sandbox Code Playgroud)

示例,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
Run Code Online (Sandbox Code Playgroud)

机床精度所特有的所有2D点:

>> xMerged = builtin('_mergesimpts',x,[eps eps],'first')
xMerged =
    1.0000    2.0000
    1.0600    2.0000
    1.1000    2.0000
    1.1000    2.0300
Run Code Online (Sandbox Code Playgroud)

基于第二维度容差的合并:

>> 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
Run Code Online (Sandbox Code Playgroud)

基于第一维度容差进行合并:

>> 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
Run Code Online (Sandbox Code Playgroud)

基于两个维度合并:

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


小智 11

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

因此,假设我们有值{A,B,C},使得isSimilarTo(A,B)为真,那么类似于(B,C)也是如此.我们是否应该决定将所有三个组合在一起,即使isSimilarTo(A,C)是假的?

更糟糕的是,转向两个维度.从围绕圆周等距间隔的k个点开始.假设选择容差使得任何点都在其直接邻居的指定容差内,但不在任何其他点上.您如何选择解决设置中哪些点"独特"?

我会声称这种不及物的问题使分组问题无法解决,至少不完美,当然也不能以任何有效的方式解决.也许有人可能会尝试基于k-means聚合方式的方法.但是这也是非常低效的,这种方法通常需要事先知道要查找的组的数量.

话虽如此,我仍然会提供妥协,有时可以在限制范围内工作.这个技巧可以在Consolidator中找到,可以在Matlab Central文件交换中找到.我的方法是有效地将输入舍入到指定的容差范围内.完成此操作后,独特和准确的组合可以有效地完成聚合,即使对于一维或多维的大型数据集也是如此.

当公差足够大以至于当多个数据属于一起时,这是一种合理的方法,它们将四舍五入到相同的值,并且通过舍入步骤偶尔会产生错误.


cha*_*pjc 9

从R2015a开始,最终有一个功能,uniquetol(在R2015a之前,请参阅我的其他答案):

uniquetol 在公差范围内设置唯一.

    uniquetol类似于unique.而unique进行精确的比较,uniquetol执行使用公差比较.

语法很简单:

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

和语义一样:

每个值C都在一个值的容差范围内A,但没有两个元素在C彼此的容差范围内.C按升序排序.两个值u,v如果符合以下条件,则在
    abs(u-v) <= TOL*max(A(:),[],1)

它也可以运行" ByRows",并且公差可以通过输入" DataScale"而不是输入数据中的最大值来缩放.

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

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

还有一个ismembertolismember上述相同的新功能.


Jon*_*nas 5

我不知道有这样的功能.一个棘手的方面是,如果你的容差是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);
Run Code Online (Sandbox Code Playgroud)

您也可以使用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
Run Code Online (Sandbox Code Playgroud)