在Matlab中,有一个unique
command返回数组中的唯一行。这是一个非常方便的命令。
但问题是我不能给它赋予公差 - 在双精度中,我们总是需要比较一个精度内的两个元素。是否有内置命令在一定容差范围内返回唯一元素?
答案 0 :(得分:12)
使用R2015a,这个问题最终有一个简单的答案(详见my other answer to this question)。对于R2015a之前的版本,有一个内置的(未记录的)函数:_mergesimpts
。对名称组成的安全猜测是“合并相似点”。
使用以下语法调用该函数:
xMerged = builtin('_mergesimpts',x,tol,[type])
数据数组x
为N-by-D
,其中N
为点数,D
为维度数。每个维度的容差由D
- 元素行向量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
合并类型:
>> 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
答案 1 :(得分: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文件交换中找到。我的方法是有效地将输入舍入到指定的容差范围内。完成此操作后,独特和准确的组合可以有效地完成聚合,即使对于一维或多维的大型数据集也是如此。
当容差足够大以至于当多个数据属于一起时,这是一种合理的方法,它们将四舍五入到相同的值,并且舍入步骤偶尔会出错。
答案 2 :(得分:7)
自R2015a 起,最后有一项功能,uniquetol
(在R2015a之前,见my other answer):
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
有关,与上述相同。
答案 3 :(得分: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);
你也可以使用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
答案 4 :(得分:4)
我之前遇到过这个问题。诀窍是首先对数据进行排序,然后使用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的文本编辑器中写的,所以可能会有一些愚蠢的错别字或一个错误。
希望有所帮助
答案 5 :(得分:0)
这很难定义,假设您的公差为1。
那么[1; 2; 3; 4]
会有什么结果呢?
当您有多个列时,定义可能会变得更具挑战性。
但是,如果您主要担心舍入问题,可以通过以下两种方法之一解决大部分问题:
unique
ismemberf
确定每个新行是否唯一,如果是,请将其添加到您的唯一设置。第一种方法的缺点是0.499999999和0.500000000可能不会被视为重复。虽然第二种方法的缺点是输入的顺序很重要。
答案 6 :(得分:0)
前几天我被 MatLab 2010 困住了,所以,没有回合(X,n),没有_mergesimpts(至少我无法让它工作)所以,一个简单的解决方案这是有效的(至少对我的数据而言):
使用rat
默认容差:
unique(cellstr(rat(x)))
其他宽容:
unique(cellstr(rat(x,tol)))