Python环境下如何实现一维数据的平衡聚类计算
一维数据均衡聚类的Python实现方案
方案适用前提
你需要同时满足两个核心要求:同簇样本数值尽可能相似、各簇样本规模差异尽可能小。针对一维数据,以下三类方案可直接落地,无复杂配置。
方案1:排序后等规模切分(纯一维场景首选,无额外依赖)
实现逻辑
一维数据无维度歧义,先对数值排序,再按目标样本量依次切分,既能保证簇规模完全可控,又能天然让数值相近的样本归为同一簇。
代码示例
import numpy as np # 输入数据 l = [46, 48, 68, 46, 48, 68, 63, 62, 63, 63, 69, 54, 64, 61, 66, 54, 64, 67, 46, 48] n_clusters = 3 n_samples = len(l) # 1. 排序并保留原索引 sorted_indices = np.argsort(l) sorted_values = np.array(l)[sorted_indices] # 2. 计算各簇目标大小:余数均匀分配到前几个簇 base_size = n_samples // n_clusters remainder = n_samples % n_clusters sizes = [base_size + 1 if i < remainder else base_size for i in range(n_clusters)] # 3. 切分生成标签 labels = np.zeros(n_samples, dtype=int) current_pos = 0 for cluster_id, size in enumerate(sizes): labels[sorted_indices[current_pos:current_pos+size]] = cluster_id current_pos += size # 验证结果 print(labels) print(np.unique(labels, return_counts=True))
运行输出的簇规模为
[7,7,6],完全符合均衡要求,各簇数值区间分别为46-54、54-64、64-69,相似性符合聚类预期。
方案2:带均衡约束的KMeans(兼顾聚类精度,可扩展到高维)
实现逻辑
在常规KMeans最小化簇内平方和的目标基础上,增加簇大小约束,保证各簇样本数差异不超过1,适合对聚类精度有要求的场景,后续扩展到高维数据也可直接复用。
前置依赖
需先安装第三方库:pip install balanced-clustering
代码示例
import numpy as np from balanced_clustering import KMeans as BalancedKMeans # 输入数据 l = [46, 48, 68, 46, 48, 68, 63, 62, 63, 63, 69, 54, 64, 61, 66, 54, 64, 67, 46, 48] X = np.array(l).reshape(-1, 1) # 初始化均衡KMeans,设置簇规模最大差值为1 b_kmeans = BalancedKMeans(n_clusters=3, max_cluster_size_diff=1) labels = b_kmeans.fit_predict(X) # 验证结果 print(labels) print(np.unique(labels, return_counts=True))
方案3:普通KMeans后处理调整(无需额外第三方依赖)
实现逻辑
先跑原生KMeans得到初始聚类结果,再将规模过大的簇中离簇中心最远的样本,调整到规模过小的最近邻簇中,直到各簇大小符合均衡要求,适合不想安装额外包的场景。
代码示例
import numpy as np from sklearn.cluster import KMeans # 输入数据 l = [46, 48, 68, 46, 48, 68, 63, 62, 63, 63, 69, 54, 64, 61, 66, 54, 64, 67, 46, 48] X = np.array(l).reshape(-1, 1) n_clusters = 3 n_samples = len(X) # 1. 先跑原生KMeans得到初始结果 kmeans = KMeans(n_clusters=n_clusters, n_init='auto') labels = kmeans.fit_predict(X) centers = kmeans.cluster_centers_ # 2. 计算每个样本到所属簇中心的距离 distances = np.abs(X.flatten() - centers[labels].flatten()) # 3. 目标最小簇大小 min_size = n_samples // n_clusters # 4. 循环调整样本归属,直到各簇规模达标 while True: counts = np.bincount(labels) large_clusters = np.where(counts > min_size)[0] small_clusters = np.where(counts < min_size)[0] if len(large_clusters) == 0 or len(small_clusters) == 0: break # 从规模最大的簇中选离中心最远的样本 large_cluster = large_clusters[np.argmax(counts[large_clusters])] large_samples = np.where(labels == large_cluster)[0] sample_to_move = large_samples[np.argmax(distances[large_samples])] # 将该样本调整到距离最近的小簇 small_centers = centers[small_clusters] new_cluster = small_clusters[np.argmin(np.abs(X[sample_to_move] - small_centers))] labels[sample_to_move] = new_cluster # 更新该样本到新簇中心的距离 distances[sample_to_move] = np.abs(X[sample_to_move] - centers[new_cluster]) # 验证结果 print(labels) print(np.unique(labels, return_counts=True))
内容的提问来源于stack exchange,提问作者MJimitater
相关产品推荐
相关产品推荐

