返回带有公差的唯一元素
在Matlab中,有这个unique
命令返回数组中唯一的行。 这是一个非常方便的命令。
但问题是,我不能容忍它 – 以双精度,我们总是必须在一个精度内比较两个元素。 有一个内置的命令返回独特的元素,在一定的宽容?
随着R2015a,这个问题终于有了一个简单的答案(详情请参阅我对这个问题的其他答案 )。 对于R2015a之前的版本,有这样一个内置(无证)function: _mergesimpts
。 对这个名字的构成进行一个安全的猜测是“合并类似的点”。
该函数使用以下语法调用:
xMerged = builtin('_mergesimpts',x,tol,[type])
数据数组x
是N-by-D
,其中N
是点数, D
是维数。 每个维度的公差由D
元素行向量tol
。 可选的input参数type
是一个string( 'first'
(default)或'average'
),指示如何合并相似的元素。
输出xMerged
将是M-by-D
,其中M<=N
它被sorting 。
例如,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
合并types:
>> 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
所有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
基于二维公差合并:
>> 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
这是一个难题。 我甚至声称这是不可能解决的,因为我称之为传递性问题。 假设我们有三个元素,{A,B,C}。 我将定义一个简单的函数isSimilarTo,如果两个input在彼此的指定容差范围内,isSimilarTo(A,B)将返回一个真实的结果。 (请注意,这里所说的一切在一个维度和多个维度都是有意义的)。所以,如果两个数字被认为是彼此“相似的”,那么我们会select将它们组合在一起。
所以假设我们有{A,B,C}的值,使得类似于(A,B)是正确的,而类似于(B,C)也是正确的。 我们是不是应该把所有这三个人组合在一起,尽pipe是类似的(A,C)是假的?
更糟的是,移动到两个维度。 从围绕圆周等间距的k个点开始。 假定容差被select为使得任何点在其直接邻居的指定容限内,但是不在任何其他点上。 你将如何select解决哪些点是“独特”的设置?
我会说这个不灵活的问题使得分组问题不可能解决,至less不是完美的,当然也不是有效的。 也许可以尝试一种基于k-means聚合风格的方法。 但是这样做效率不高,这种方法一般需要事先知道要查找的小组数量。
话虽如此,我仍然会提供一个妥协,有时可以在限制范围内工作。 这个技巧可以在Matlab Central文件交换中find。 我的做法是有效地将投入集中在指定的容差范围内。 这样做以后,独特和准确的结合可以有效地完成聚合,即使对于一个或多个维度的大量数据集也是如此。
这是一个合理的方法,当容差足够大,当多个数据片段归在一起时,它们将四舍五入成为相同的值,偶尔会出现舍入步骤的错误。
至于R2015a ,最后还是有这个function呢 , uniquetol ( 在R2015a之前 ,看我的其他答案 ):
uniquetol
在公差范围内设置独特。
uniquetol
类似于unique
。 而unique
执行精确的比较,uniquetol
使用容差进行比较。
语法很简单:
C = uniquetol(A,TOL)
使用公差TOL
返回A
的唯一值。
同样的语义:
C
每个值在A
的一个值的容差范围内,但C
中没有两个元素在彼此的容差范围内。C
按升序排列。 在以下情况下,u
和v
两个值在容差范围内:
abs(uv) <= TOL*max(A(:),[],1)
它也可以操作“ ByRows
”,公差可以通过input“ DataScale
”进行缩放,而不是通过input数据中的最大值进行缩放。
但是关于解决scheme的独特性有一个重要的说明:
可以有多个有效的
C
输出满足条件,“C
中没有两个元素在彼此的容忍范围内”。 例如,在A
交换列可能会导致返回不同的解决scheme,因为input是按列按字典顺序sorting的。 另一个结果是uniquetol(-A,TOL)
可能与-uniquetol(A,TOL)
。
ismembertol
还有一个新的function,就是和上面相同的方法。
没有我知道的这样的function。 一个棘手的方面是,如果你的容忍度是1e-10,而你有一个向量的值是9e-11,那么第一个和第三个条目是不一样的,但是第一个和第三个条目是一样的第二个,第二个和第三个是一样的 – 那么有多less“唯一”呢?
解决这个问题的一个办法就是把你的数值四舍五入到所需要的精确度,然后运行它。 您可以使用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
我之前遇到过这个问题。 诀窍是首先对数据进行sorting,然后使用diff函数查找每个项目之间的差异。 那么比较一下这个差距是否小于你的容忍度。 这是我使用的代码:
tol = 0.001 [YI] = 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
这不关心“漂stream”…所以像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,所以可能会有一些愚蠢的错别字或closures一个错误。
希望有所帮助
这很难定义好,假设你有1的容忍度。那么[1; 2; 3; 4]
[1; 2; 3; 4]
[1; 2; 3; 4]
?
当你有多个列时,定义可能变得更具挑战性。
但是,如果您主要担心四舍五入问题,则可以通过以下两种方法之一来解决大部分问题:
- 舍入所有的数字(考虑你的容忍度),然后使用
unique
- 从顶行开始,作为唯一集合,使用
ismemberf
来确定每个新行是否是唯一的,如果是,则将其添加到唯一集合中。
第一种方法有0.499999999和0.500000000可能不被视为重复的弱点。 虽然第二种方法有你的input顺序很重要的弱点。
前几天我被MatLab 2010卡住了,所以,没有轮(X,n),没有_mergesimpts(至less我不能工作),所以,一个简单的解决scheme(至less对我的数据)起作用:
使用rat
默认容差:
unique(cellstr(rat(x)))
其他宽容:
unique(cellstr(rat(x,tol)))