如何高效将DataFrame列中的唯一值转换为哑变量新列?
高效生成分类列哑变量的解决方案
这问题我太熟悉了!手动写apply逐行处理确实效率拉胯,尤其是当分类值多、数据量大的时候,完全没必要这么干——Pandas和Scikit-learn都有专门的向量化工具,性能直接拉满。
方法一:Pandas内置pd.get_dummies(最推荐,简单高效)
这是处理这类需求的标准工具,底层是向量化实现,速度比自定义apply快几个数量级。
保留原timeline列的写法
import pandas as pd df2 = pd.DataFrame( {"id":[1001,1002,1003,1004], "is_male":[1,0,0,1], "is_elder":[0,0,0,1], "timeline":["b1","b2","c","b1"]} ) # 生成timeline列的哑变量,设置空前缀让列名直接是分类值 dummy_cols = pd.get_dummies(df2['timeline'], prefix='', prefix_sep='') # 横向合并原DataFrame和哑变量列 df_result = pd.concat([df2, dummy_cols], axis=1) print(df_result)
输出完全符合你的预期:
| id | is_male | is_elder | timeline | b1 | b2 | c |
|---|---|---|---|---|---|---|
| 1001 | 1 | 0 | b1 | 1 | 0 | 0 |
| 1002 | 0 | 0 | b2 | 0 | 1 | 0 |
| 1003 | 0 | 0 | c | 0 | 0 | 1 |
| 1004 | 1 | 1 | b1 | 1 | 0 | 0 |
替换原timeline列的写法
如果不需要保留原timeline列,可以直接指定columns参数一步到位:
df_result = pd.get_dummies(df2, columns=['timeline'], prefix='', prefix_sep='')
方法二:Scikit-learn的OneHotEncoder(适合机器学习场景)
如果后续要做机器学习建模,用OneHotEncoder更灵活——它支持稀疏矩阵输出(节省内存,尤其当分类值极多的时候),还能和Pipeline无缝集成。
import pandas as pd from sklearn.preprocessing import OneHotEncoder df2 = pd.DataFrame( {"id":[1001,1002,1003,1004], "is_male":[1,0,0,1], "is_elder":[0,0,0,1], "timeline":["b1","b2","c","b1"]} ) # 初始化编码器,sparse_output=False返回密集矩阵,方便转DataFrame encoder = OneHotEncoder(sparse_output=False, drop=None) # 注意要传入二维数组(所以用[['timeline']]而不是['timeline']) encoded_data = encoder.fit_transform(df2[['timeline']]) # 获取哑变量的列名 dummy_col_names = encoder.get_feature_names_out(['timeline']) # 转成DataFrame并和原数据合并 encoded_df = pd.DataFrame(encoded_data, columns=dummy_col_names, index=df2.index) df_result = pd.concat([df2, encoded_df], axis=1) # 如果想去掉列名里的"timeline_"前缀,可以重命名 df_result.columns = df_result.columns.str.replace('timeline_', '')
为什么这些方法比自定义apply高效?
自定义apply是逐行遍历处理,属于Python层面的循环,时间复杂度是O(n);而pd.get_dummies和OneHotEncoder都是基于底层向量化运算(C/C++实现),能一次性处理整列数据,速度提升非常明显——当你的数据量达到几万甚至几十万行、分类值超过10个时,这个差距会肉眼可见。
内容的提问来源于stack exchange,提问作者KT.Thompson
相关产品推荐
相关产品推荐

