轮廓分数计算的高效并行化实现方案问询
问题分析与解决
错误原因
你的并行实现逻辑完全错误:Parallel(n_jobs=36)需要接收一个任务迭代器,但你只传入了单次调用silhouette_samples(data, labels)的任务;同时silhouette_samples返回的是一维数组,joblib内部处理时会错误尝试拆包返回值,最终导致"not enough values to unpack"报错。
另外,你完全没必要手动用joblib实现并行——scikit-learn的轮廓分数计算函数本身已经内置了多核并行支持,直接指定参数就能高效利用36核资源。
可行解决方案
方案1:使用sklearn内置并行(推荐)
silhouette_score和silhouette_samples都支持n_jobs参数,直接设置为核数即可,sklearn内部会自动完成并行优化,比手动实现更稳定高效:
from sklearn.metrics import silhouette_score from sklearn.cluster import MiniBatchKMeans # 拟合MiniBatchKMeans kmeans = MiniBatchKMeans(n_clusters=50, batch_size=1000, random_state=42) kmeans.fit(data) labels = kmeans.labels_ # 直接用内置并行计算轮廓分数 score = silhouette_score(data, labels, n_jobs=36)
如果需要获取每个样本的轮廓值再求平均,同样可以用silhouette_samples的n_jobs参数:
from sklearn.metrics import silhouette_samples import numpy as np silhouette_values = silhouette_samples(data, labels, n_jobs=36) average_score = np.mean(silhouette_values)
方案2:手动用joblib拆分数据并行(仅作参考,不推荐)
如果一定要手动实现并行,需要将数据集拆分为多个子集,分别计算每个子集的轮廓值后再合并结果:
from sklearn.metrics import silhouette_samples from sklearn.cluster import MiniBatchKMeans from joblib import Parallel, delayed import numpy as np # 拟合MiniBatchKMeans kmeans = MiniBatchKMeans(n_clusters=50, batch_size=1000, random_state=42) kmeans.fit(data) labels = kmeans.labels_ # 将数据集拆分为36个批次 num_splits = 36 data_splits = np.array_split(data, num_splits) label_splits = np.array_split(labels, num_splits) # 并行计算每个批次的轮廓值 silhouette_parts = Parallel(n_jobs=36)( delayed(silhouette_samples)(data_split, label_split) for data_split, label_split in zip(data_splits, label_splits) ) # 合并结果并计算平均分 silhouette_values = np.concatenate(silhouette_parts) average_score = np.mean(silhouette_values)
额外优化建议
- 针对200万行的数据集,可尝试调整
MiniBatchKMeans的batch_size(比如设为2000或5000),平衡内存占用与拟合速度。 - 如果需要测试多个
n_clusters值,可将整个K-Means拟合+轮廓分数计算的过程并行化:
def compute_score(n_clusters): kmeans = MiniBatchKMeans(n_clusters=n_clusters, batch_size=1000, random_state=42) labels = kmeans.fit_predict(data) return silhouette_score(data, labels, n_jobs=1) # 每个任务用1核,总核数由Parallel控制 # 并行测试多个簇数 cluster_range = [30, 40, 50, 60, 70] scores = Parallel(n_jobs=6)(delayed(compute_score)(n) for n in cluster_range)
内容的提问来源于stack exchange,提问作者AbliusKarfax
相关产品推荐
相关产品推荐

