如何用Pandas高效实现字典映射的哑特征生成(含类别特征)
我之前处理过类似的动态特征生成需求,硬写循环确实太不灵活了——尤其是字典里的类别和动物数量经常变的时候。下面给你几个高效且易维护的实现方案,从简洁到性能优化的都有:
方案1:简洁的列表推导式+Concat组合
这个方案代码量少,易读性高,适合字典结构比较简单的场景:
import pandas as pd random_animals = pd.DataFrame( {'description':['xdogx','xcatx','xhamsterx','xdogx' ,'xhorsex','xdonkeyx','xcatx']} ) cat_dict = {'category_a':['dog','cat'] ,'category_b':['horse','donkey']} # 批量生成单个动物的特征列 animal_features = pd.concat( [ random_animals['description'].str.contains(animal, regex=False).astype(int).rename(f'is_{animal}') for category in cat_dict.values() for animal in category ], axis=1 ) # 合并原数据与动物特征列 result_df = pd.concat([random_animals, animal_features], axis=1) # 批量生成类别特征列:只要类别下有一个动物匹配,就标记为1 for cat_name, animal_list in cat_dict.items(): result_df[f'is_{cat_name}'] = result_df[[f'is_{animal}' for animal in animal_list]].any(axis=1).astype(int) print(result_df)
思路说明:
- 用列表推导式遍历字典中所有动物,一次性生成所有
is_{animal}列,再用pd.concat合并,避免了逐列赋值的循环; - 类别特征列利用
any(axis=1)判断该类别下是否有动物匹配,转成int类型得到0/1结果,逻辑清晰。
方案2:基于透视表的灵活映射法
如果你的字典结构可能更复杂(比如多层嵌套、多对多映射),这个方案的扩展性更强:
import pandas as pd random_animals = pd.DataFrame( {'description':['xdogx','xcatx','xhamsterx','xdogx' ,'xhorsex','xdonkeyx','xcatx']} ) cat_dict = {'category_a':['dog','cat'] ,'category_b':['horse','donkey']} # 把字典展开为「类别-动物」的映射DataFrame category_mapping = pd.DataFrame( [(cat, animal) for cat, animals in cat_dict.items() for animal in animals], columns=['category', 'animal'] ) # 提取所有匹配的动物,生成标记 matched_animals = random_animals['description'].str.extractall(f"({'|'.join(category_mapping['animal'])})")[0].reset_index() matched_animals['value'] = 1 # 透视生成单个动物的特征列 animal_pivot = matched_animals.pivot(index='level_0', columns='0', values='value').fillna(0).astype(int) animal_pivot.columns = [f'is_{col}' for col in animal_pivot.columns] # 合并原数据与动物特征列 result_df = random_animals.join(animal_pivot, how='left').fillna(0).astype(int) # 基于映射表生成类别特征列 cat_feature_df = animal_pivot.T.join(category_mapping.set_index('animal')['category']).groupby('category').sum().T cat_feature_df.columns = [f'is_{col}' for col in cat_feature_df.columns] # 合并类别特征列 result_df = result_df.join(cat_feature_df) print(result_df)
思路说明:
- 先把字典转成结构化的映射表,后续所有操作都基于这个表,避免硬编码;
- 用
extractall一次性提取所有匹配的动物,再通过透视表生成特征列,适配多匹配场景; - 类别特征列通过分组求和生成,自动适配类别下的动物数量变化。
方案3:Numpy矩阵加速的高性能方案
如果你的数据集很大(十万级以上行),这个方案利用Numpy的矩阵操作大幅提升性能:
import pandas as pd import numpy as np random_animals = pd.DataFrame( {'description':['xdogx','xcatx','xhamsterx','xdogx' ,'xhorsex','xdonkeyx','xcatx']} ) cat_dict = {'category_a':['dog','cat'] ,'category_b':['horse','donkey']} # 提取所有动物的列表 all_animals = [animal for animals in cat_dict.values() for animal in animals] # 生成匹配矩阵:每行对应一条数据,每列对应一个动物的匹配结果 match_matrix = np.array([ random_animals['description'].str.contains(animal, regex=False) for animal in all_animals ]).T.astype(int) # 转成动物特征DataFrame animal_features = pd.DataFrame(match_matrix, columns=[f'is_{animal}' for animal in all_animals]) # 合并原数据 result_df = pd.concat([random_animals, animal_features], axis=1) # 生成类别特征列:用sum+clip替代any,性能更优 for cat_name, animal_list in cat_dict.items(): result_df[f'is_{cat_name}'] = result_df[[f'is_{a}' for a in animal_list]].sum(axis=1).clip(0, 1).astype(int) print(result_df)
思路说明:
- 用Numpy把所有匹配结果转成二维矩阵,相比多次
concat,矩阵操作的内存效率和计算速度更高; - 用
sum(axis=1).clip(0,1)替代any(axis=1),在大数据量下性能提升明显,结果完全一致。
内容的提问来源于stack exchange,提问作者user4505419
相关产品推荐
相关产品推荐

