如何将SKLearn KMeans的cluster_centers_正确映射到原始DataFrame?
解决KMeans cluster_centers_与原始DataFrame列名不匹配的问题
我明白你碰到的麻烦了——预处理过程中调整了特征(删原列加二值化列),导致聚类用的特征顺序和原始DataFrame对不上,直接给cluster_centers_套原始列名自然会错位。下面给你一步步解决的办法,还有能避免下次踩坑的技巧:
第一步:先锁定聚类时用的真实特征列
你最后用来训练KMeans的那个DataFrame(就是做完标准化、二值化、删加列之后的),先把它的列名存下来,这才是和cluster_centers_对应的特征顺序:
# 假设这个处理后的DataFrame叫processed_df cluster_feature_names = processed_df.columns.tolist()
然后先给聚类中心匹配正确的特征名:
import pandas as pd # 先让聚类中心和处理后的特征列对应上 centers_df = pd.DataFrame(k_means.cluster_centers_, columns=cluster_feature_names)
第二步:映射回原始DataFrame的列
接下来要把这些聚类中心值对应回原始DataFrame的列,得根据你的预处理步骤拆分处理:
区分标准化列和二值化列处理
假设你是把原始的两列(比如colX、colY)换成了二值化列(比如colX_bin、colY_bin),剩下的列是标准化后的:
- 先拆分出标准化列和二值化列:
# 按你的二值化列命名规则来筛选,这里假设后缀是_bin scaled_cols = [col for col in cluster_feature_names if not col.endswith('_bin')] bin_cols = [col for col in cluster_feature_names if col.endswith('_bin')]
- 对标准化列做逆变换(注意要用处理后的特征顺序):
# 先把标准化列按MinMaxScaler拟合时的原始列顺序排序(保证逆变换的维度正确) scaled_cols_sorted = [col for col in scaler.feature_names_in_ if col in scaled_cols] scaled_centers = centers_df[scaled_cols_sorted] # 执行逆变换 scaled_centers_inversed = scaler.inverse_transform(scaled_centers) scaled_centers_inversed_df = pd.DataFrame(scaled_centers_inversed, columns=scaled_cols_sorted)
- 合并逆变换后的列和二值化列,再按原始DataFrame的列顺序排列:
# 合并两类列 merged_centers = pd.concat([scaled_centers_inversed_df, centers_df[bin_cols]], axis=1) # 按原始DataFrame的列顺序重新整理,得到最终对应正确的聚类中心 final_centers = merged_centers[df.columns]
预防踩坑:用Pipeline封装预处理+聚类
下次别手动一步步改特征了,用SKLearn的Pipeline和ColumnTransformer把预处理和聚类封装在一起,它会自动跟踪特征顺序,根本不会出现列错位的问题:
from sklearn.pipeline import Pipeline from sklearn.preprocessing import MinMaxScaler, Binarizer from sklearn.compose import ColumnTransformer from sklearn.cluster import KMeans # 定义预处理:指定哪些列做标准化,哪些做二值化 preprocessor = ColumnTransformer( transformers=[ ('scaler', MinMaxScaler(), ['feat1', 'feat4', 'feat5']), # 替换成你要标准化的列 ('binarizer', Binarizer(threshold=0.5), ['feat2', 'feat3']) # 替换成你要二值化的列 ]) # 把预处理和KMeans打包成Pipeline pipeline = Pipeline(steps=[ ('preprocessor', preprocessor), ('kmeans', KMeans(n_clusters=4)) ]) # 直接用原始DataFrame训练 pipeline.fit(df) # 获取处理后的特征名,和聚类中心对应 processed_feature_names = pipeline.named_steps['preprocessor'].get_feature_names_out() centers_df = pd.DataFrame(pipeline.named_steps['kmeans'].cluster_centers_, columns=processed_feature_names) # 要逆变换的话,直接从Pipeline里取对应的scaler scaler = pipeline.named_steps['preprocessor'].named_transformers_['scaler'] # 提取标准化后的聚类中心列,去掉前缀 scaled_centers = centers_df.filter(regex='scaler__') scaled_centers.columns = [col.replace('scaler__', '') for col in scaled_centers.columns] # 逆变换 scaled_centers_inversed = scaler.inverse_transform(scaled_centers) scaled_centers_inversed_df = pd.DataFrame(scaled_centers_inversed, columns=scaled_centers.columns) # 提取二值化列,去掉前缀 bin_centers = centers_df.filter(regex='binarizer__') bin_centers.columns = [col.replace('binarizer__', '') for col in bin_centers.columns] # 合并后按原始列顺序排列 final_centers = pd.concat([scaled_centers_inversed_df, bin_centers], axis=1)[df.columns]
这样整个流程都被标准化管理,特征顺序不会乱,后续维护也方便。
内容的提问来源于stack exchange,提问作者Tomi Gelo
相关产品推荐
相关产品推荐

