我在某个任意空间中拥有n数据点,并将它们聚类。 我的聚类算法的结果是一个分区,由l长度为 的int 向量表示n,将每个点分配给一个聚类。 的值范围l从 0 到(可能)n-1。
n
l
n-1
例子:
l_1 = [ 1 1 1 0 0 2 6 ]
将点划分n=7为 4 个簇:前三个点聚集在一起,第四个和第五个点聚集在一起,最后两个点形成两个不同的单簇。
n=7
假设我有两个分区l_1,l_2如何有效地确定它们是否代表相同的分区?
l_1
l_2
l_2 = [ 2 2 2 9 9 3 1 ]
等同于,l_1因为它表示点的相同分区(尽管簇的“数字”/“标签”并不相同)。 另一方面
l_3 = [ 2 2 2 9 9 3 3 ]
由于它将最后两点组合在一起,因此不再相同。
我正在寻找 C++、python 或 Matlab 的解决方案。
一种简单的方法是比较共现矩阵
c1 = bsxfun( @eq, l_1, l_1' ); c2 = bsxfun( @eq, l_2, l_2' ); l_1_l_2_are_identical = all( c1(:)==c2(:) );
共现矩阵的c1大小为nx,n如果true点k和m位于同一簇中,则为 ,false否则为 (无论簇“编号”/“标签”如何)。 因此,如果共现矩阵c1和c2相同,则l_1和l_2代表相同的分区。
c1
true
k
m
false
c2
然而,由于点的数量n可能非常大,因此我想避免 O( n^2) 解决方案......
n^2
有什么想法吗?
谢谢!
为了有效判断两个分区是否相同,而无需使用 ( O(n^2) ) 的共现矩阵方法,可以通过 标准化标签 的方式实现 ( O(n \log k) ) 或 ( O(n) ) 的复杂度,其中 ( k ) 是簇的数量(通常 ( k \ll n ))。以下是解决方案:
标准化标签: 将每个分区的簇标签重新映射为一个固定顺序的规范形式。例如,将 [1, 1, 1, 0, 0, 2, 6] 标准化为 [0, 0, 0, 1, 1, 2, 3],这样不同分区的标签顺序无关,便于直接比较。
[1, 1, 1, 0, 0, 2, 6]
[0, 0, 0, 1, 1, 2, 3]
直接比较: 标准化后的两个分区可以通过简单的逐元素比较来判断是否相同。
import numpy as np def normalize_labels(labels): """将簇标签标准化为固定顺序的形式""" _, normalized_labels = np.unique(labels, return_inverse=True) return normalized_labels def are_partitions_identical(l1, l2): """判断两个分区是否相同""" # 将分区标签标准化 normalized_l1 = normalize_labels(l1) normalized_l2 = normalize_labels(l2) # 比较标准化后的分区 return np.array_equal(normalized_l1, normalized_l2) # 示例 l1 = [1, 1, 1, 0, 0, 2, 6] l2 = [2, 2, 2, 9, 9, 3, 1] l3 = [2, 2, 2, 9, 9, 3, 3] print(are_partitions_identical(l1, l2)) # 输出: True print(are_partitions_identical(l1, l3)) # 输出: False
在 C++ 中,可以使用 std::unordered_map 来实现类似的标签标准化:
std::unordered_map
#include <vector> #include <unordered_map> #include <algorithm> #include <iostream> std::vector<int> normalize_labels(const std::vector<int>& labels) { std::unordered_map<int, int> label_map; std::vector<int> normalized_labels; int next_label = 0; for (int label : labels) { if (label_map.find(label) == label_map.end()) { label_map[label] = next_label++; } normalized_labels.push_back(label_map[label]); } return normalized_labels; } bool are_partitions_identical(const std::vector<int>& l1, const std::vector<int>& l2) { if (l1.size() != l2.size()) return false; return normalize_labels(l1) == normalize_labels(l2); } // 示例 int main() { std::vector<int> l1 = {1, 1, 1, 0, 0, 2, 6}; std::vector<int> l2 = {2, 2, 2, 9, 9, 3, 1}; std::vector<int> l3 = {2, 2, 2, 9, 9, 3, 3}; std::cout << std::boolalpha; std::cout << "l1 和 l2 是否相同: " << are_partitions_identical(l1, l2) << std::endl; // 输出: true std::cout << "l1 和 l3 是否相同: " << are_partitions_identical(l1, l3) << std::endl; // 输出: false return 0; }
在 Matlab 中,可以使用 unique 函数来标准化标签:
unique
function identical = are_partitions_identical(l1, l2) % 将标签标准化为固定形式 normalized_l1 = normalize_labels(l1); normalized_l2 = normalize_labels(l2); % 比较标准化后的标签 identical = isequal(normalized_l1, normalized_l2); end function normalized_labels = normalize_labels(labels) [~, ~, normalized_labels] = unique(labels, 'stable'); end % 示例 l1 = [1 1 1 0 0 2 6]; l2 = [2 2 2 9 9 3 1]; l3 = [2 2 2 9 9 3 3]; disp(are_partitions_identical(l1, l2)); % 输出: true disp(are_partitions_identical(l1, l3)); % 输出: false
np.unique
总复杂度:( O(n \log k) ) 或 ( O(n) )。
空间复杂度:
这种方法避免了 ( n \times n ) 共现矩阵的构造,适用于大规模数据。无论是 Python、C++ 还是 Matlab 实现,都具有清晰的逻辑和较高的效率。