在Matlab中,有一个unique
命令可以返回数组中的唯一行.这是一个非常方便的命令.
但问题在于我不能为它赋予容差 - 在双精度中,我们总是需要比较精度内的两个元素.是否有内置命令在特定容差范围内返回唯一元素?
cha*_*pjc 13
使用R2015a,这个问题最终得到了一个简单的答案(详情请参阅我对这个问题的其他答案).对于R2015a之前的版本,有一个内置的(未记录的)功能:_mergesimpts
.对名称组成的安全猜测是"合并相似点".
使用以下语法调用该函数:
xMerged = builtin('_mergesimpts',x,tol,[type])
Run Code Online (Sandbox Code Playgroud)
数据数组x
是点数N-by-D
,其中N
是D
维数.每个维度的容差由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文件交换中找到.我的方法是有效地将输入舍入到指定的容差范围内.完成此操作后,独特和准确的组合可以有效地完成聚合,即使对于一维或多维的大型数据集也是如此.
当公差足够大以至于当多个数据属于一起时,这是一种合理的方法,它们将四舍五入到相同的值,并且通过舍入步骤偶尔会产生错误.
从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)
.
还有一个ismembertol
与ismember
上述相同的新功能.
我不知道有这样的功能.一个棘手的方面是,如果你的容差是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)