Python中DataFrame行相似性检测:合并分类目标类简化模型
解决多类别分类任务中的类别合并问题
核心目标
通过合并特征相似的类别,将50个类别缩减至更易处理的数量,同时维持原数据集的概率分布基本不变。
具体实现方案
1. 先做类别级特征聚合,而非样本级聚类
不能直接对单条数据行聚类,而是先为每个原始类别生成特征聚合表征:
- 数值特征:计算该类别下各特征的均值、中位数或分位数统计量
- 类别特征:统计该类别下各特征的众数或频率分布
每个原始类别会对应一个固定的特征向量,后续的相似性判断都基于这个向量。
2. 选择适配的相似性度量
根据特征类型选合适的相似性指标:
- 纯数值聚合特征:用欧氏距离、余弦相似度或曼哈顿距离
- 混合类型特征:用Gower距离(专门处理数值+类别混合数据的相似性计算)
3. 带分布约束的聚类合并
用聚类算法合并类别时,加入分布保护规则:
- 层次聚类:通过树状图手动控制合并阈值,优先合并特征最相似的类别,过程中可以实时观察每个合并组的样本占比,确保和原类别占比之和一致
- K-Means聚类:提前设定目标类别数(比如从50降到20),但需要限制每个聚类组的样本占比,与被合并的原始类别占比总和偏差不超过预设阈值(比如5%)
- 核心原则:合并后的新类别样本占比 = 被合并的所有原始类别样本占比之和,保证整体概率分布不偏移
4. 分布一致性验证
合并后必须验证分布是否符合要求:
- 统计原数据集每个类别的样本占比,对比合并后新类别对应的占比之和,用KL散度或卡方检验衡量分布差异,数值越小说明分布越接近
- 检查特征分布:对每个特征,用KS检验对比原类别组和合并后新类别的特征分布,确保差异在可接受范围内
伪代码示例
# 1. 生成每个类别的特征聚合向量 class_feature_profiles = df.groupby('Y').agg({ 'x1': 'mean', 'x2': 'median', 'x3': 'mean' }).values # 2. 计算类别间相似性矩阵 from sklearn.metrics.pairwise import cosine_similarity similarity_matrix = cosine_similarity(class_feature_profiles) # 3. 层次聚类合并类别 from scipy.cluster.hierarchy import linkage, fcluster linkage_result = linkage(class_feature_profiles, method='ward') # 设定合并后的目标类别数为20 cluster_labels = fcluster(linkage_result, t=20, criterion='maxclust') # 4. 映射原始类别到新类别 class_mapping = {y: f'val_{c}' for y, c in zip(df['Y'].unique(), cluster_labels)} df['New Y'] = df['Y'].map(class_mapping) # 5. 验证分布偏差 original_dist = df['Y'].value_counts(normalize=True) new_dist = df['New Y'].value_counts(normalize=True) from scipy.stats import entropy kl_divergence = entropy(original_dist, new_dist) print(f"分布差异KL散度: {kl_divergence}")
关键注意点
- 优先合并小样本类别:样本量极少的类别,即使特征差异稍大,也可合并到最相似的类别,避免分布失衡
- 避免样本级聚类:直接聚类单条数据会打散同一类别的样本,导致合并逻辑混乱
- 迭代调整:先尝试合并到30个类别,验证分布后再逐步缩减,找到模型性能和分布一致性的平衡点
内容的提问来源于stack exchange,提问作者Bhaskar
相关产品推荐
相关产品推荐

