unique
命令,可以返回数组中唯一的行。这是非常方便的命令。但问题是我不能为它分配公差--在双精度下,我们总是必须在精度范围内比较两个元素。是否有一个内置的命令,可以返回在某个公差范围内的唯一元素?
随着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
griddata
如何识别“重复”点时发现了它。很遗憾,这个功能没有适当的文档说明。请随意编辑此帖以更正我的错误。我记得有一些不准确或至少缺少一些细节,但从未有时间深入挖掘并使其100%正确。 - chappjc话虽如此,我仍然会提供一种妥协方案,有时可以在限制范围内起作用。技巧在于Consolidator,可以在Matlab中心文件交换中找到。我的方法是将输入有效地舍入到指定的公差范围内。这样做后,unique和accumarray的组合使得即使对于一个或多个维度中的大数据集,聚合也可以高效完成。
当公差足够大以至于多个数据块属于同一组时,它们将被舍入为相同的值,舍入步骤可能会偶尔出现错误,这时这种方法就是一个合理的选择。
uniquetol
(在R2015a之前,参见我的另一个回答):
语法很简单:
uniquetol
是设置容差范围内的唯一值。
uniquetol
类似于unique
。其中unique
执行精确比较,而uniquetol
使用容差进行比较。
语义也很清晰:
C = uniquetol(A,TOL)
使用容差TOL
返回A
中的唯一值。
它也可以按行操作,并且容差可以通过输入的"
C
的每个值与A
的一个值在容差范围内,但C
中的任何两个元素都不在容差范围内。C
按升序排列。如果满足以下条件,则两个值u
和v
在容差范围内:
abs(u-v) <= TOL*max(A(:),[],1)
DataScale
"进行缩放,而不是通过输入数据中的最大值进行缩放。还有一个新函数满足“
C
中的任何两个元素都不在容差范围内”条件的多个有效C
输出可能存在。例如,交换A
中的列可能会导致返回不同的解决方案,因为输入按列按词典顺序排序。另一个结果是,uniquetol(-A,TOL)
可能与-uniquetol(A,TOL)
的结果不同。
ismembertol
与上面类似地与ismember
相关。我不知道有这样的函数。一个棘手的问题是,如果你的容差是1e-10,而你有一个向量,其值在9e-11处等间隔分布,第一个和第三个条目不相同,但第一个与第二个相同,第二个与第三个相同 - 那么有多少个“唯一”的元素?
解决这个问题的一种方法是将您的值四舍五入到所需的精度,然后对其运行unique。您可以使用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);
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
我以前遇到过这个问题。 技巧是首先对数据进行排序,然后使用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的文本编辑器中编写的,所以可能会有一些愚蠢的拼写错误或者偏移一个字符的错误。
希望这有所帮助。
使用默认公差的rat:
unique(cellstr(rat(x)))
其他公差:
unique(cellstr(rat(x,tol)))
这很难定义清楚,假设你有一个容差为1。
那么[1; 2; 3; 4]
的结果会是什么?
当你有多列时,定义可能会变得更加具有挑战性。
然而,如果你主要担心舍入问题,你可以通过以下两种方法解决大部分问题:
unique
ismemberf
来确定每一行是否唯一,如果是,则将其添加到你的唯一集合中。第一种方法的弱点在于0.499999999和0.500000000可能不被视为重复项。而第二种方法的弱点在于输入的顺序很重要。