使用Sklearn GridSearchCV调优HDBSCAN时DBCV得分偏低问题排查
问题分析
- 核心错误:
make_scorer生成的评分器默认要求函数接收y_true和y_pred两个参数,但无监督聚类没有真实标签y_true,而hdbscan.validity.validity_index的签名是(X, labels),参数不匹配触发TypeError。 - GridSearchCV总是选第一个参数的原因:评分函数未正确计算有效得分,所有参数组合的得分可能为默认值(或相同值),因此返回第一个条目。
解决方案
1. 适配无监督场景的DBCV评分器
sklearn的无监督评分器要求函数签名为(estimator, X),我们可以基于HDBSCAN拟合后的labels_属性自定义评分器:
def dbcv_scorer(estimator, X): # 从拟合后的模型中获取聚类标签,计算DBCV labels = estimator.labels_ return hdbscan.validity.validity_index(X, labels) # 生成符合sklearn规范的评分器 validity_scorer = make_scorer(dbcv_scorer, greater_is_better=True)
2. 修正GridSearchCV的初始化逻辑
不要提前拟合HDBSCAN模型,GridSearchCV会自动为每个参数组合重新拟合模型:
# 错误写法:hdb = hdbscan.HDBSCAN(...).fit(coordinates) # 正确写法:仅初始化未拟合的模型实例 hdb = hdbscan.HDBSCAN(gen_min_span_tree=True)
3. 完整修正代码
from sklearn.model_selection import GridSearchCV import hdbscan from sklearn.metrics import make_scorer import logging logging.captureWarnings(True) # 初始化未拟合的HDBSCAN模型 hdb = hdbscan.HDBSCAN(gen_min_span_tree=True) # 定义参数网格 grid = { 'min_samples': [50,55,60,65,70,75,80,90,100,110], 'min_cluster_size': [40,45,50,55,60,65,75,80,85,90,95,100], 'cluster_selection_method': ['eom','leaf'], 'metric': ['euclidean','manhattan'] } # 自定义DBCV评分器 def dbcv_scorer(estimator, X): labels = estimator.labels_ return hdbscan.validity.validity_index(X, labels) validity_scorer = make_scorer(dbcv_scorer, greater_is_better=True) # 初始化GridSearchCV grid_search = GridSearchCV( estimator=hdb, param_grid=grid, scoring=validity_scorer, # 可选:指定交叉验证策略,无监督场景推荐用ShuffleSplit # cv=ShuffleSplit(n_splits=5, test_size=0.2, random_state=42) ) # 执行网格搜索 grid_search.fit(coordinates) # 输出最优结果 print(f"Best Parameters {grid_search.best_params_}") print(f"Cross-validated DBCV score :{grid_search.best_score_}")
4. RandomizedSearchCV的参数记录方案
用RandomizedSearchCV时,开启return_train_score=True,将所有参数组合的得分保存到DataFrame,方便回溯最优参数:
from sklearn.model_selection import RandomizedSearchCV import pandas as pd random_search = RandomizedSearchCV( estimator=hdb, param_distributions=grid, n_iter=20, # 随机采样20组参数 scoring=validity_scorer, return_train_score=True, random_state=42 ) random_search.fit(coordinates) # 转换结果为DataFrame并按得分排序 results_df = pd.DataFrame(random_search.cv_results_) results_df_sorted = results_df.sort_values(by='mean_test_score', ascending=False) # 查看Top5最优参数组合 print(results_df_sorted[['params', 'mean_test_score']].head())
关键说明
- 无监督聚类的评分器必须适配sklearn的无监督接口,不能直接用默认的
make_scorer包装有监督风格的函数。 - 提前拟合模型会导致GridSearchCV复用已训练的模型,无法正确测试不同参数组合,必须传入未拟合的模型实例。
grid_search.best_score_是交叉验证后的平均DBCV得分,和手动单次拟合的得分可能略有差异,但能更客观反映参数的稳定性。
内容的提问来源于stack exchange,提问作者MJM
相关产品推荐
相关产品推荐

