【问题标题】:How to find closest (nearest) value within a vector to another vector?如何在一个向量中找到最接近(最近)的值到另一个向量?
【发布时间】:2016-06-12 10:23:27
【问题描述】:

我有两个大小相等的向量,例如

A=[2.29 2.56 2.77 2.90 2.05] and
B=[2.34 2.62 2.67 2.44 2.52].

我有兴趣在两个相同大小的向量 A 和 B 中找到最接近的值(几乎相等),即在 A 的所有元素中,哪个值最接近 B 的任何元素?该解决方案也应该可以扩展到任意数量(相等大小)的向量。意味着能够使用一组相同大小的向量 A、B 和 C 找到最接近的值。两个结果值可以来自两个向量中的任何一个。

为了清楚起见,我不想在单个向量中找到最接近的值。以上示例的答案是值 2.56 和 2.52。

【问题讨论】:

    标签: arrays matlab vector distance


    【解决方案1】:

    这适用于通用数量可能不同长度的向量

    vectors = {[2.29 2.56 2.77 2.90 2.05] [2.34 2.62 2.67 2.44 2.52] [1 2 3 4]}; 
        % Cell array of data vectors; 3 in this example
    s = cellfun(@numel, vectors); % Get vector lengths
    v = [vectors{:}]; % Concatenate all vectors into a vector
    D = abs(bsxfun(@minus, v, v.')); % Compute distances. This gives a matrix.
        % Distances within the same vector will have to be discarded. This will be
        % done by replacing those values with NaN, in blocks
    bb = arrayfun(@(x) NaN(x), s, 'uniformoutput', false); % Cell array of blocks
    B = blkdiag(bb{:}); % NaN mask with those blocks
    [~, ind] = min(D(:) + B(:)); % Add that mask. Get arg min in linear index
    [ii, jj] = ind2sub(size(D), ind); % Convert to row and column indices
    result = v([ii jj]); % Index into concatenated vector
    

    【讨论】:

    • 哇,不错的解决方案!
    • 我借用了你的blkdiag 想法;)+1,
    • 代码工作正常。也适用于不同的向量长度。
    • @thewaywewalk 好!答案也不错!
    • @thewaywewalk 是的,现在您不再使用组合 (nchoosek),它们更相似
    【解决方案2】:

    使用bsxfun作为两个向量的起点:

    %// data
    A = [2.29 2.56 2.77 2.90 2.05]
    B = [2.34 2.62 2.67 2.44 2.52]
    
    %// distance matrix 
    dist = abs(bsxfun(@minus,A(:),B(:).'));
    
    %// find row and col indices of minimum
    [~,idx] = min(dist(:))
    [ii,jj] = ind2sub( [numel(A), numel(B)], idx)
    
    %// output 
    a = A(ii)
    b = B(jj)
    

    现在您可以将其放入循环等中。


    顺便说一句:

    dist = abs(bsxfun(@minus,A(:),B(:).'));
    

    会等价于更明显的:

    dist = pdist2( A(:), B(:) )
    

    但我宁愿选择第一个解决方案,避免开销。


    最后是多向量的完全向量化方法:

    %// data
    data{1} = [2.29 2.56 2.77 2.90 2.05];
    data{2} = [2.34 2.62 2.67 2.44 2.52];
    data{3} = [2.34 2.62 2.67 2.44 2.52].*2;
    data{4} = [2.34 2.62 2.67 2.44 2.52].*4;
    %// length of each vector
    N = 5;
    
    %// create Filter for distance matrix
    nans(1:numel(data)) = {NaN(N)};
    mask = blkdiag(nans{:}) + 1; 
    
    %// create new input for bsxfun
    X = [data{:}];
    
    %// filtered distance matrix 
    dist = mask.*abs(bsxfun(@minus,X(:),X(:).'));
    
    %// find row and col indices of minimum
    [~,idx] = min(dist(:))
    [ii,jj] = ind2sub( size(dist), idx)
    
    %// output 
    a = X(ii)
    b = X(jj)
    

    【讨论】:

    • 代码适用于两个向量。如何将其扩展到三个或更多向量?
    • @erbal 所有向量的长度都一样吗?
    • @erbal 这是一个相对较新的功能,看看这里的 SO,你会找到一个替代品
    • @erbal 我用blkdiag(受Luis Mendo 启发)改进了我的解决方案,你不再需要repelem,而且内存更少;)
    • 现在正在尝试更新代码,因为无法在任何地方找到 repelem。
    【解决方案3】:

    就像长评论,如果您可以访问 Statistics and Machine Learning Toolbox,那么您可以使用 K-Nearest Neighbors 函数,这些函数具有以下优点:

    1. 处理不同长度的数组,例如 size(A) = [M, 1] 和 size(B) = [N, 1]

    2. 处理二维数组,例如当 size(A) = [M, d] 和 size(B) = [N, d]

    3. 处理不同的距离类型,例如:欧几里得、城市街区、切比雪夫等等,甚至您拥有自定义距离

    4. 在某些特殊情况下使用 KDTree 算法会产生出色的性能。

    虽然在您的情况下,“Luis Mendo”的答案看起来很不错,但它不能像工具箱提供的 K-Nearest Neighbors 函数那样扩展。

    更新:示例代码

    % A and B could have any Dimension, just same number of columns (signal Dimension)
    A = rand(1000,4);
    B = rand(500,4);
    
    % Use any distance you like, some of them are not supported for KDTreeSearcher,
    % and you should use ExhaustiveSearcher
    myKnnModel= KDTreeSearcher(A, 'Distance', 'minkowski');
    
    % you can ask for many (K) Nearest Neighbors and you always have access to it for later uses
    [Idx, D] = knnsearch(myKnnModel, B, 'K',2);
    
    % and this is answer to your special case
    [~, idxA] = min(D(:, 1))
    idxB = Idx(idxA)
    

    【讨论】:

    • 这看起来很有希望。也许添加一个带有两个或三个向量的示例以使其成为真正的答案?
    • @LuisMendo。我已经用示例代码更新了我的答案,请检查它并告诉我您的想法。
    • 这是一个非常好的概括。我想你有idxBidxAswapped:应该是[~, idxB] = min(D(:, 1)); idxA = Idx(idxB); 对吧?也许还需要补充一点,所需的最近向量是 A(idxA,:)B(idxB,:)
    • @LuisMendo。我目前无权访问 MATLAB 来检查代码。只需检查 D 的大小,如果 size(D, 1) == size(B, 1) ,那么你是对的,
    • @LuisMendo:我无法破译这段代码。如果您可以访问 matlab,请针对我的问题重新发布/纠正此代码。
    猜你喜欢
    • 1970-01-01
    • 2022-08-14
    • 1970-01-01
    • 2011-02-22
    • 2020-02-05
    • 1970-01-01
    • 2022-09-27
    • 2012-05-25
    相关资源
    最近更新 更多