在Matlab中删除长行数据点

Remove long row of data points in Matlab

我有一个坐标列表,coord,绘制时看起来像这样:

我想从数据集中删除从 0 到 1 的一长串点,显示在该图上,从 (0, 11) 开始到 (1, 11) 结束,另一个是从 (0, 24) 开始,到 (1, 28) 结束。

到目前为止,我已尝试使用 kmeans 使用以下代码按高度对数据进行分组:

jet = colormap('jet');

amount = 20;
step = floor(numel(jet(:,1))/amount);
idxOIarr = cell(numel(terp));
scale = 100;

for ii = 1:numel(terp)
    figure;
    hold on;
    expandDat = [stretched{ii}(:,1), scale.*log(terp{ii}(:,2))];
    [idx, cent] = kmeans(expandDat(:,1:2), amount, 'Distance', 'cityblock');
    idxOIarr{ii} = idx;
    for jj = 1:amount
        scatter(stretched{ii}(idx == jj,1), FREQ(terp{ii}(idx == jj,2)), 10, jet(step*jj,:), 'filled');
    end
end

生成此图像: 虽然它确实很好地分隔了较高的行,但它将中间的行分成两部分,并将从 (0,20) 开始的行与一些数据点分组在它下面。

有没有其他方法可以对这些点进行分组和删除?

解决这个问题的最有效方法是构建一个图,其中每个点都是一个顶点。您将您认为 "connected" 或 "closed" 的点与一条边连接起来。因此,该图将连接组件。现在您需要寻找跨越从 0 到 1 的整个范围的连通分量。

  1. 构建图形。使用 R 树查找邻居最有效。 Here are some suggestions。例如,您还可以使用 k-d 树。然而,这并不是绝对必要的,如果没有适当的空间索引结构,它会变得非常慢,因为您必须比较每对点之间的距离。

    给定一个 Nx2 矩阵 coord,你可以找到每对之间的平方距离:

    D = sum((reshape(coord,[],1,2) - reshape(coord,1,[],2)).^2,3);
    

    (再次注意,如果 N 很大,这会很昂贵,在这种情况下,使用 R 树会显着加快速度)。 D(i,j) 是索引为 ij 的点之间的距离(即 coord(i,:)coord(j,:).

    接下来,构建图,G,如果G(i,j)==1,节点ij是连接的。 G是对称矩阵:

    G = D <= max_distance;
    
  2. 求连通分量。连接的组件只是一组节点,您可以通过跟随边从彼此到达这些节点。你真的不需要找到所有连通分量,你只需要找到具有x=0的点集,并从每个点开始,递归访问其连通分量中的所有元素,看是否可以到达一个点有 x=1.

    下一段代码未经测试,但它提供了一个起点:

    start_indices = find(coord(:,1)==0);  % Is exact equality appropriate here?
    end_indices = find(coord(:,1)==1);
    to_remove = [];
    visited = false(size(coord,1), 1);
    for ii=start_indices.'
       % For each point with x=0, see if we can reach any of the points at x=1
       [res, visited] = can_reach(ii, end_indices, G, visited);
       if res
          % For this point we can, remove it!
          to_remove(end+1) = ii;
       end
    end
    
    % Iterative function to visit all nodes in a connected component
    function [res, visited] = can_reach(start, end_indices, G, visited)
       visited(start) = true;
       if any(start==end_indices)
          % We've reach an end point, stop iterating and return true.
          res = true;
          return;
       end
       next = find(G(start,:));  % find neighbors
       next(visited(next)) = []; % remove visited neighbors
       for ii=next
          [res, visited] = can_reach(ii, end_indices, G, visited);
          if res
             % Yes, we can visit an end point, stop iterating now.
             return
          end
       end
    end