如何对高基数交易号分类变量编码以适配k-means及层次聚类?
前置问题答疑
OrdinalEncoder和pandas.to_numeric手动转序数没有本质区别,都是给每个唯一的transaction分配任意整数,完全无法解决聚类时的虚假距离问题,不推荐使用。
方案1:业务语义编码(最优)
你当前的transaction是收款方+付款方的拼接值,本质是交易对手对,完全可以基于这个分类值的统计属性转成有实际业务意义的数值特征,完全避免维度爆炸和虚假距离问题:
- 统计每个
transaction的累计交易次数(代表交易对活跃度) - 统计每个
transaction的平均/最大/中位数交易金额(代表交易对的资金规模特征)
示例代码:
# 统计每个交易对的交易次数和平均金额 tran_stats = df.groupby('transaction')['amount'].agg(['count', 'mean']).reset_index() tran_stats.columns = ['transaction', 'tran_count', 'tran_avg_amount'] # 统计结果映射回原数据集 df = df.merge(tran_stats, on='transaction', how='left') # 删掉原transaction列 df.drop(columns=['transaction'], inplace=True)
该方案仅新增2列特征,内存消耗可以忽略不计,且生成的特征完全符合业务逻辑,聚类时的距离计算结果天然合理。
方案2:特征哈希(Hashing Trick)
如果你需要保留交易对的标识信息不想做统计聚合,可以用哈希技巧把高基数分类值映射到固定低维的稀疏向量,维度可以根据内存自由调整(比如设置为128/256维),不会出现one-hot的维度爆炸问题,也不会引入序数编码的虚假距离:
示例代码:
from sklearn.feature_extraction import FeatureHasher n_features = 128 # 维度越高信息损失越小,可根据内存调整 hasher = FeatureHasher(n_features=n_features, input_type='string') hash_features = hasher.transform(df['transaction'].astype(str)) # 转成DataFrame和原有特征合并 hash_df = pd.DataFrame(hash_features.toarray(), columns=[f'tran_hash_{i}' for i in range(n_features)]) df = pd.concat([df.drop(columns=['transaction']), hash_df], axis=1)
方案3:低频归类降基数
如果以上两种都不满足需求,可以先把出现频率低的transaction统一归为一类,大幅降低唯一值数量后再做编码:
# 仅保留出现次数≥5的交易对,其余归为「其他」 tran_count = df['transaction'].value_counts() keep_tran = tran_count[tran_count >=5].index df['transaction'] = df['transaction'].where(df['transaction'].isin(keep_tran), other='其他')
处理后唯一值通常会降到几千甚至几百的量级,此时再做one-hot编码内存也完全足够。
额外注意事项
k-means和层次聚类都基于欧氏距离计算,所有特征处理完成后必须做标准化/归一化,避免金额、日期等特征的量纲差异影响聚类结果。
内容的提问来源于stack exchange,提问作者Slazer
相关产品推荐
相关产品推荐

