如何计算分类变量的匹配距离?求无需独热编码的替代算法
问题:无需独热编码的混合类型数据距离计算替代方案
我曾尝试用Gower距离计算数据集的距离矩阵,代码能正常运行,但发现这个方法不符合需求——Gower距离对连续变量用曼哈顿距离,二元变量用Dice距离计算相似度,所以必须把所有多分类(类别数>2)的变量做独热编码转成哑变量。但我不想用独热编码,想找替代算法,有没有合适的选择?
数据集
{'Sex': {0: 'Female', 1: 'Female', 2: 'Female', 3: 'Female', 4: 'Male', 5: 'Male', 6: 'Female', 7: 'Female', 8: 'Female', 9: 'Male', 10: 'Male', 11: 'Female', 12: 'Female', 13: 'Female', 14: 'Female'}, 'City': {0: 'Lagos', 1: 'Lagos', 2: 'Tokyo', 3: 'London', 4: 'Tokyo', 5: 'Lagos', 6: 'Cairo', 7: 'Lagos', 8: 'Lagos', 9: 'Tokyo', 10: 'Houston', 11: 'New York', 12: 'Lagos', 13: 'Paris', 14: 'Chicago'}, 'Region': {0: 'Africa', 1: 'Africa', 2: 'Asia Pacific', 3: 'Europe', 4: 'Asia Pacific', 5: 'Africa', 6: 'Africa', 7: 'Africa', 8: 'Africa', 9: 'Asia Pacific', 10: 'Americas', 11: 'Americas', 12: 'Africa', 13: 'Europe', 14: 'Americas'}, 'Graduated': {0: 'No', 1: 'Yes', 2: 'Yes', 3: 'No', 4: 'Yes', 5: 'Yes', 6: 'Yes', 7: 'No', 8: 'Yes', 9: 'Yes', 10: 'No', 11: 'Yes', 12: 'No', 13: 'Yes', 14: 'No'}}
当前实现代码
import pandas as pd import numpy as np import gower df=pd.read_csv("k_mode_data.csv") distance_matrix = gower.gower_matrix(df) cat_df = pd.DataFrame(distance_matrix)
推荐替代方案
1. K-Prototypes 距离(适配混合类型数据)
K-Prototypes专为混合数值/分类数据设计,无需独热编码:对分类变量采用简单匹配逻辑(取值相同则距离为0,不同则为1),数值变量用欧氏距离。可以直接利用kmodes库的距离计算功能:
from kmodes.kprototypes import KPrototypes from kmodes.util import dissim import pandas as pd import numpy as np df = pd.read_csv("k_mode_data.csv") # 将分类列转为category类型 for col in df.columns: df[col] = df[col].astype('category') # 获取所有分类列的索引 cat_cols_idx = [df.columns.get_loc(col) for col in df.columns] # 生成全量距离矩阵 distance_matrix = np.zeros((len(df), len(df))) for i in range(len(df)): for j in range(len(df)): distance_matrix[i,j] = dissim(df.iloc[i].values, df.iloc[j].values, cat_cols_idx, cat_metric='hamming') cat_df = pd.DataFrame(distance_matrix)
2. Hamming 距离(纯分类数据场景)
如果你的数据集全是分类变量(如示例数据),Hamming距离是最直接的选择:统计两个样本中取值不同的变量占比,无需任何编码。用scikit-learn即可快速实现:
import pandas as pd from sklearn.metrics.pairwise import pairwise_distances df = pd.read_csv("k_mode_data.csv") # 将分类列转为标签编码(非独热,仅映射为整数) df_encoded = df.apply(lambda x: x.astype('category').cat.codes) # 计算Hamming距离矩阵 distance_matrix = pairwise_distances(df_encoded, metric='hamming') cat_df = pd.DataFrame(distance_matrix)
3. 自定义距离函数(完全灵活控制)
如果需要自定义分类变量的距离逻辑(比如给不同变量分配权重),可以自己实现距离函数:
import pandas as pd import numpy as np df = pd.read_csv("k_mode_data.csv") def custom_cat_distance(s1, s2, weights=None): # s1、s2为单个样本的Series if weights is None: weights = {col:1 for col in s1.index} # 计算每个分类变量的差异:不同则为1,相同则为0,乘以权重 diffs = [(s1[col] != s2[col]) * weights[col] for col in s1.index] return sum(diffs) / sum(weights.values()) # 生成距离矩阵 distance_matrix = np.zeros((len(df), len(df))) for i in range(len(df)): for j in range(len(df)): # 可自定义权重,比如给City列更高权重:weights={'Sex':1, 'City':2, 'Region':1, 'Graduated':1} distance_matrix[i,j] = custom_cat_distance(df.iloc[i], df.iloc[j]) cat_df = pd.DataFrame(distance_matrix)
内容的提问来源于stack exchange,提问作者yocodefreak
相关产品推荐
相关产品推荐

