#python #scikit-learn #gridsearchcv
#питон #scikit-учиться #gridsearchcv
Вопрос:
Я использую GridSearchCV, чтобы найти наилучшую настройку параметров моего оценщика sklearn.pipeline. Конвейер состоит из преобразования данных, уменьшения размера UMAP и кластеризации Kmeans. Окончательные результаты кластеризации Kmeans оцениваются с помощью silhouette_score. Я попытался проверить правильность работы всего конвейера / GridSearchCV, изменив только порядок параметров в param_grid (например, измените ‘уменьшить__n_соседей’: (5, 10) на ‘уменьшить__n_соседей’: (10, 5)). Я получил совершенно другие наилучшие параметры, хотя я ожидаю, что изменение порядка параметров не должно влиять на наилучшие параметры, определенные GridSearchCV.
Ниже приведен код. Класс Debug используется для сохранения выходных данных с шага «уменьшить». Этот сохраненный результат используется в cv_silhouette_scorer() для вычисления silhouette_score. Я подозреваю, что класс отладки и cv_silhouette_scorer() работали не так, как я ожидал.
Большое вам спасибо за вашу помощь.
class Debug(BaseEstimator, TransformerMixin):
def __init__(self):
self.transX = None
def transform(self, X):
print(X)
self.transX = X.copy()
return X
def fit(self, X, y=None, **fit_params):
return self
def cv_silhouette_scorer(estimator, X):
# estimator.fit(X)
sdata = estimator.named_steps['debug'].transX
cluster_labels = estimator.named_steps['cluster'].labels_
num_labels = len(set(cluster_labels))
num_samples = sdata.shape[0]
if num_labels == 1 or num_labels == num_samples:
return -1
else:
return silhouette_score(sdata, cluster_labels)
ohe = OneHotEncoder(drop='if_binary', dtype=np.float32)
ore = OrdinalEncoder(dtype=np.float32)
ctenc = ColumnTransformer(transformers=[('ohe', ohe, nom_vars), ('ore', ore, ord_vars)],
remainder='passthrough')
nftr = FunctionTransformer(nominal_indicator_missing, check_inverse=False,
kw_args={'feat_names': ohecols, 'orig_cols': nom_vars})
oftr = FunctionTransformer(ordinal_indicator_missing, check_inverse=False,
kw_args={'miss_value': 0.})
ctmiss = ColumnTransformer(transformers=[('nftr', nftr, slice(0, 19)), ('oftr', oftr, slice(19, 20)), ('drop_cols', 'drop' , slice(32, 36) )], remainder='passthrough')
mputer = IterativeImputer(random_state=RS, add_indicator=True, initial_strategy="most_frequent", skip_complete=True)
# Add below keep_vars transformer to drop all demographic columns before pass to UMAP
keep_cols = ColumnTransformer(transformers=[('keep_cols1', 'passthrough' , slice(17, 25) ), ('keep_cols2', 'passthrough' , slice(46, 54) )] )
scaler = StandardScaler()
trans = FunctionTransformer(np.transpose, check_inverse=False)
dreduce = umap.UMAP(random_state=RS)
knn = KMeans(random_state=RS)
pipe = Pipeline(steps=[
('enc', ctenc)
, ('functr', ctmiss)
, ('mpute', mputer)
, ('keep_cols', keep_cols)
, ('scale', scaler)
, ('trans', trans)
, ('reduce', dreduce)
, ("debug", Debug())
, ('cluster', knn)
]
)
parameters = {
'mpute__max_iter': (15, 20),
'reduce__n_neighbors': (5, 10),
'reduce__min_dist': (0.02, 0.05),
'reduce__n_components': (2, 3),
'reduce__metric': ('euclidean', 'manhattan'),
'cluster__n_clusters': (2, 3),
'cluster__n_init': (10, 25)
}
# parameters = {
# 'mpute__max_iter': (20, 15),
# 'reduce__n_neighbors': (10, 5),
# 'reduce__min_dist': (0.05, 0.02),
# 'reduce__n_components': (3, 2),
# 'reduce__metric': ('manhattan', 'eucidean'),
# 'cluster__n_clusters': (3, 2),
# 'cluster__n_init': (25, 10)
# }
def cv_silhouette_scorer(estimator, X):
# estimator.fit(X)
sdata = estimator.named_steps['debug'].transX
cluster_labels = estimator.named_steps['cluster'].labels_
num_labels = len(set(cluster_labels))
num_samples = sdata.shape[0]
if num_labels == 1 or num_labels == num_samples:
return -1
else:
return silhouette_score(sdata, cluster_labels)
gsearch3 = GridSearchCV(pipe, parameters, n_jobs=-1, scoring=cv_silhouette_scorer , cv=5, verbose=1)
gsearch3.fit(dfnew)