如何将多列视为一组进行One Hot Encoding编码?
对DataFrame分组列执行联合One-Hot编码
我明白你的需求:你希望把多列同类型的数据当成一个组来做One-Hot编码,比如Countries1和Countries2合并后取唯一值生成统一的类别列,而不是单独对每列编码。下面我给你两种实用的实现方案,用Python的pandas和sklearn都能搞定。
先看示例数据
假设你的DataFrame长这样:
import pandas as pd df = pd.DataFrame({ 'Countries1': ['USA', 'Canada'], 'Cities1': ['NY', 'Toronto'], 'Countries2': ['Canada', 'Mexico'], 'Cities2': ['Vancouver', 'Mexico City'] })
你要把列索引[0,2](对应Countries1和Countries2)作为一组,[1,3](对应Cities1和Cities2)作为另一组,生成合并后的One-Hot列。
方案1:纯Pandas实现(无需额外库)
这种方法逻辑直观,适合小数据集,不用依赖sklearn:
def group_one_hot_encode(df, column_groups, group_names=None): encoded_dfs = [] # 给分组默认命名,也支持自定义 if group_names is None: group_names = [f"Group{i}" for i in range(len(column_groups))] for group_name, cols in zip(group_names, column_groups): # 取出当前分组的所有列(兼容列索引和列名两种传入方式) group_cols = df.iloc[:, cols] if isinstance(cols[0], int) else df[cols] # 获取该分组所有唯一值(去重后排序保证一致性) unique_vals = sorted(pd.unique(group_cols.values.ravel())) # 为每个唯一值生成One-Hot列 for val in unique_vals: # 每行只要分组内任意一列等于该值,就标记为1,否则0 encoded_col = group_cols.apply(lambda row: 1 if val in row.values else 0, axis=1) encoded_col.name = f"{group_name}_{val}" encoded_dfs.append(encoded_col) # 合并原DataFrame和编码后的列,也可以选择删除原分组列(注释里有代码) result_df = pd.concat([df] + encoded_dfs, axis=1) # 可选:删除原分组列 # all_group_cols = [col for group in column_groups for col in group] # result_df = result_df.drop(df.columns[all_group_cols], axis=1) return result_df # 调用函数:传入列索引分组,也可以直接传列名比如[['Countries1','Countries2'], ['Cities1','Cities2']] encoded_df = group_one_hot_encode(df, [[0,2], [1,3]], group_names=['Country', 'City']) print(encoded_df)
输出结果
Countries1 Cities1 Countries2 Cities2 Country_Canada Country_Mexico Country_USA City_Mexico City City_NY City_Toronto City_Vancouver 0 USA NY Canada Vancouver 1 0 1 0 1 0 1 1 Canada Toronto Mexico Mexico City 1 1 0 1 0 1 0
方案2:用Sklearn的MultiLabelBinarizer(更高效)
如果你的数据集较大,用sklearn的工具会更高效,代码也更简洁:
from sklearn.preprocessing import MultiLabelBinarizer def group_one_hot_encode_sklearn(df, column_groups, group_names=None): encoded_dfs = [] if group_names is None: group_names = [f"Group{i}" for i in range(len(column_groups))] for group_name, cols in zip(group_names, column_groups): group_cols = df.iloc[:, cols] if isinstance(cols[0], int) else df[cols] # 把每行的多列值转换成一个列表(比如['USA', 'Canada']) rows_as_lists = group_cols.values.tolist() # 用MultiLabelBinarizer生成编码 mlb = MultiLabelBinarizer() encoded_data = mlb.fit_transform(rows_as_lists) # 转换成DataFrame并命名列 encoded_df = pd.DataFrame(encoded_data, columns=[f"{group_name}_{val}" for val in mlb.classes_]) encoded_dfs.append(encoded_df) result_df = pd.concat([df] + encoded_dfs, axis=1) # 可选删除原分组列 # all_group_cols = [col for group in column_groups for col in group] # result_df = result_df.drop(df.columns[all_group_cols], axis=1) return result_df # 调用函数 encoded_df_sklearn = group_one_hot_encode_sklearn(df, [[0,2], [1,3]], group_names=['Country', 'City']) print(encoded_df_sklearn)
这个方法和方案1的输出完全一致,但处理大数据集时速度更快,而且是sklearn的标准工具,稳定性更好。
注意事项
- 缺失值处理:如果你的分组列里有
NaN,两种方法都会把NaN当成一个类别生成对应的编码列。如果不需要,可以先对原DataFrame做缺失值填充(比如df.fillna('Unknown', inplace=True))或者删除缺失行。 - 列名灵活性:你可以根据需求修改编码列的命名规则,比如去掉分组前缀,或者用更贴合业务的名称。
- 原列保留:函数默认保留原DataFrame的列,如果你不需要,可以取消注释里的删除代码。
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

