基于等价性将值分组在一起
Grouping values together based on equivalence
我有一个 Nx2 矩阵(在本例中为 6X2),如下所示:
5 4
8 6
9 8
10 9
15 14
16 15
我想按以下方式对它们进行分组:
*(5,4) 是第一组。它与剩余的行一起检查。由于5和4都没有出现在剩余的行中,所以可以保持原样。
*(8,6) 是下一组。然而在第 3 行 8 再次出现为 (9,8)。所以它连接到第二组,即第二组变成(8,6,9,8)。
*下一个(10,9)是seen.But 9属于第2组,10也加进去了。所以第二组现在是 (8,6,9,8,10,9)。
*看到下一个(15,14)。到目前为止,它还没有出现或重复。所以它变成了第三组即(15,14)。
*终于看到了(16,15)。但由于 15 在第 3 组中重复出现,该组现在更新为 (15,14,16,15)。
最后可以使用MATLAB中的unique
命令去除组中的冗余元素
我希望最终输出为组数:
5 4
8 6 9 10
15 14 16
注意:行组中元素的顺序并不重要,因为 (5,4) 或 (4,5) 是相同的。另外我猜,最终输出可能附加了零,以使其成为一个等维矩阵,即
5 4 0 0
8 6 9 10
15 14 16 0
请帮忙。谢谢。
这让我想起了一个一般的聚类问题。 Cuthill-McKee 算法正是您要搜索的内容,尽管它通常用不同的术语表示。好消息是Matlab在symrcm
函数中实现了它。
这是一段适用于您的示例的代码。请注意,它非常强大,并且还能够处理更复杂的数据集:
% --- Definition
D = [5 4 ; 8 6 ; 9 8 ; 10 9 ; 15 14 ; 16 15];
N = max(D(:));
U = unique(D(:));
% --- Tansformation to adjacency matrix
A = sparse(N,N);
% Diagonal element
for i = 1:numel(U)
A(U(i),U(i)) = 1;
end
% Adjacency links
for i = 1:size(D,1)
A(D(i,1),D(i,2)) = 1;
A(D(i,2),D(i,1)) = 1;
end
% --- Cuthill Mc-Kee algorithm
r = symrcm(A);
% --- Find the clusters
% Preparation
B = (A(r,r)^N)>0;
i = 1;
C = {};
% Find clusters iteratively
while i<=N
if ~any(B(:,i))
i = i+1;
else
I = find(B(:,i));
i = max(I)+1;
C{end+1} = r(I);
end
end
% --- Display
for i = 1:numel(C)
disp(C{i})
end
和输出:
5 4
10 9 8 6
16 15 14
最佳,
所以,我觉得应该有一种方法可以使用基于树的算法或 disjoint-set/union-find 类型的方法来做到这一点。但是对于可能不是那么有效的肮脏的第一种方法,我编写了以下代码:
A = [5 4
8 6
9 8
10 9
15 14
16 15
8 8
3 4
3 1
];
B = mat2cell(A,ones(size(A,1),1),2);
iter = 1;
while(true)
if (iter > size(B,1))
break
end
y = B{iter};
C = cat(1,false(iter,1),cellfun(@(x) any(sum(bsxfun(@eq,x,y'))),B(iter+1:end)));
if any(C)
B{iter} = (cat(2,B{iter}, B{C}));
% or put you can start shortening them here, by calling unique() already:
%B{iter} = unique(cat(2,B{iter}, B{C}));
B(C) = [];
else
iter = iter+1;
end
end
B = cellfun(@unique,B,'uni',false);
B{:}
效果还不错。我不知道这是否能满足您的需求,但快速编写代码很有趣。感谢您提出有趣的问题。
我有一个 Nx2 矩阵(在本例中为 6X2),如下所示:
5 4
8 6
9 8
10 9
15 14
16 15
我想按以下方式对它们进行分组:
*(5,4) 是第一组。它与剩余的行一起检查。由于5和4都没有出现在剩余的行中,所以可以保持原样。
*(8,6) 是下一组。然而在第 3 行 8 再次出现为 (9,8)。所以它连接到第二组,即第二组变成(8,6,9,8)。
*下一个(10,9)是seen.But 9属于第2组,10也加进去了。所以第二组现在是 (8,6,9,8,10,9)。
*看到下一个(15,14)。到目前为止,它还没有出现或重复。所以它变成了第三组即(15,14)。
*终于看到了(16,15)。但由于 15 在第 3 组中重复出现,该组现在更新为 (15,14,16,15)。
最后可以使用MATLAB中的unique
命令去除组中的冗余元素
我希望最终输出为组数:
5 4
8 6 9 10
15 14 16
注意:行组中元素的顺序并不重要,因为 (5,4) 或 (4,5) 是相同的。另外我猜,最终输出可能附加了零,以使其成为一个等维矩阵,即
5 4 0 0
8 6 9 10
15 14 16 0
请帮忙。谢谢。
这让我想起了一个一般的聚类问题。 Cuthill-McKee 算法正是您要搜索的内容,尽管它通常用不同的术语表示。好消息是Matlab在symrcm
函数中实现了它。
这是一段适用于您的示例的代码。请注意,它非常强大,并且还能够处理更复杂的数据集:
% --- Definition
D = [5 4 ; 8 6 ; 9 8 ; 10 9 ; 15 14 ; 16 15];
N = max(D(:));
U = unique(D(:));
% --- Tansformation to adjacency matrix
A = sparse(N,N);
% Diagonal element
for i = 1:numel(U)
A(U(i),U(i)) = 1;
end
% Adjacency links
for i = 1:size(D,1)
A(D(i,1),D(i,2)) = 1;
A(D(i,2),D(i,1)) = 1;
end
% --- Cuthill Mc-Kee algorithm
r = symrcm(A);
% --- Find the clusters
% Preparation
B = (A(r,r)^N)>0;
i = 1;
C = {};
% Find clusters iteratively
while i<=N
if ~any(B(:,i))
i = i+1;
else
I = find(B(:,i));
i = max(I)+1;
C{end+1} = r(I);
end
end
% --- Display
for i = 1:numel(C)
disp(C{i})
end
和输出:
5 4
10 9 8 6
16 15 14
最佳,
所以,我觉得应该有一种方法可以使用基于树的算法或 disjoint-set/union-find 类型的方法来做到这一点。但是对于可能不是那么有效的肮脏的第一种方法,我编写了以下代码:
A = [5 4
8 6
9 8
10 9
15 14
16 15
8 8
3 4
3 1
];
B = mat2cell(A,ones(size(A,1),1),2);
iter = 1;
while(true)
if (iter > size(B,1))
break
end
y = B{iter};
C = cat(1,false(iter,1),cellfun(@(x) any(sum(bsxfun(@eq,x,y'))),B(iter+1:end)));
if any(C)
B{iter} = (cat(2,B{iter}, B{C}));
% or put you can start shortening them here, by calling unique() already:
%B{iter} = unique(cat(2,B{iter}, B{C}));
B(C) = [];
else
iter = iter+1;
end
end
B = cellfun(@unique,B,'uni',false);
B{:}
效果还不错。我不知道这是否能满足您的需求,但快速编写代码很有趣。感谢您提出有趣的问题。