我想从 Matlab 上的向量中删除重复的条目。我遇到的问题是舍入错误正在阻止内置的 Matlab 函数“唯一”正常工作。理想情况下,我想要一种在“独特”功能上设置某种容差的方法,或者是一个可以删除重复项的小程序。如果两个条目的实部和虚部相差小于 0.0001,那么我很乐意认为它们相等。我怎样才能做到这一点?
任何帮助将不胜感激。谢谢
我想从 Matlab 上的向量中删除重复的条目。我遇到的问题是舍入错误正在阻止内置的 Matlab 函数“唯一”正常工作。理想情况下,我想要一种在“独特”功能上设置某种容差的方法,或者是一个可以删除重复项的小程序。如果两个条目的实部和虚部相差小于 0.0001,那么我很乐意认为它们相等。我怎样才能做到这一点?
任何帮助将不胜感激。谢谢
一个简单的近似是对数字进行四舍五入并使用唯一返回的索引:
X = ... (input vector)
[b, i] = unique(round(X / (tolerance * (1 + i))));
output = X(i);
(您可以根据您的 Matlab 版本替换为)b
。~
它不会完全具有您想要的行为,因为两个数字可能非常接近,但会以不同的方式四舍五入。我认为您可以通过以下方式减轻这种情况:
X = ... (input vector)
[b, ind] = unique(round(X / (tolerance * (1 + i))));
X = X(ind);
[b, ind] = unique(round(X / (tolerance * (1 + i)) + 0.5 * (1 + i)));
X = X(ind);
这会将它们四舍五入两次,因此恰好在舍入边界上的任何数字都将被第二个捕获unique
。这仍然有些混乱——一些数字会受到影响,就好像容差翻了一番。但这可能足以满足您的需求。
替代方案可能是一个for
循环:
X = sort(X);
last = X(1);
indices = ones(numel(X), 1);
for j=2:numel(X)
if X(j) > last + tolerance * (1 + i)
last = X(j) + tolerance * (1 + i) / 2;
else
indices(j) = 0;
end
end
X = X(logical(indices));
我认为这具有您可以期望的最佳行为(因为您希望用尽可能少的唯一值来表示向量 - 当有很多数字的差异小于容差水平时,可能有多种拆分它们的方法。这个算法贪婪地做,从最小的开始)。
以下内容可能符合您的目的。给定一个复数双精度数组 X,它对它们进行排序,然后检查元素之间的绝对值差是否在复数容差 real_tol 和 imag_tol 内。它会删除满足此容差的元素。
function X_unique = unique_complex_with_tolerance(X,real_tol,imag_tol)
X_sorted = sort(X); %Sorts by magnitude first, then imaginary part.
dX_sorted = diff(X_sorted);
dX_sorted_real = real(dX_sorted);
dX_sorted_imag = imag(dX_sorted);
remove_idx = (abs(dX_sorted_real)<real_tol) & (abs(dX_sorted_imag)<imag_tol);
X_unique = X_sorted;
X_unique(remove_idx) = [];
return
请注意,此代码将删除所有满足此差异容差的元素。例如,如果 X = [1+i,2+2i,3+3i,4+4i],real_tol = 1.1,imag_tol = 1.1,那么这个函数将只返回一个元素,X_unique = [4+4i],甚至尽管您可能会认为,例如 X_unique = [1+i,4+4i] 也是一个有效答案。
我几乎可以肯定下面的错误总是假设任何接近 1e-8 的值都是相等的。只需将 1e-8 替换为您想要的任何值。
% unique function that assumes 1e-8 is equal
function [out, I] = unique(input, first_last)
threshold = 1e-8;
if nargin < 2
first_last = 'last';
end
[out, I] = sort(input);
db = diff(out);
k = find(abs(db) < threshold);
if strcmpi(first_last, 'last')
k2 = min(I(k), I(k+1));
elseif strcmpi(first_last, 'first')
k2 = max(I(k), I(k+1));
else
error('unknown flag option for unique, must be first or last');
end
k3 = true(1, length(input));
k3(k2) = false;
out = out(k3(I));
I = I(k3(I));
end