如何用Pandas基于已有DataFrame高效创建含二进制列的新DataFrame
高效实现DataFrame的二进制编码(替代循环方法)
嘿,我完全懂你遇到的痛点——嵌套循环处理大型数据集时,那种慢到让人抓狂的感觉真的不好受!其实Pandas和Scikit-learn有专门的矢量化/批量处理工具,能帮你以快得多的速度完成这个二进制编码需求,而且代码更简洁。
先明确你的需求:把原DataFrame每行的每个元素,对应到新DataFrame的列(比如prod_xxx),出现过的标记为1,没出现的为0。下面分两种常见场景给你最优方案:
场景1:原DataFrame是宽格式(每行对应一个样本,每列是单个产品项)
比如你的products是这样的结构(每行是一个用户,每列是他购买的一个产品):
import pandas as pd products = pd.DataFrame({ 'item1': ['A', 'B', 'C'], 'item2': ['B', 'D', None], 'item3': ['A', 'C', 'D'] })
最优实现代码
用stack() + get_dummies() + groupby().sum()的组合,全程矢量化操作,比循环快几个数量级:
# 1. 把所有元素堆叠成Series,保留原行索引 stacked_products = products.stack() # 2. 生成二值化编码,再按原索引分组求和(同一行的多个产品合并为1) products_coded = pd.get_dummies(stacked_products, prefix='prod').groupby(level=0).sum()
这样得到的products_coded就是每行对应原DataFrame的行,每列是prod_A、prod_B这类,值为1或0的结果。
场景2:原DataFrame是长格式(每行是一个样本,单元格是产品列表)
如果你的products是每行存一个产品列表的结构:
products = pd.DataFrame({ 'user_products': [['A', 'B'], ['B', 'D'], ['A', 'C', 'D']] })
最优实现代码
用Scikit-learn的MultiLabelBinarizer,专门处理多标签的二值化:
from sklearn.preprocessing import MultiLabelBinarizer # 初始化二值化器 mlb = MultiLabelBinarizer() # 生成编码结果,转成DataFrame并加上前缀 products_coded = pd.DataFrame( mlb.fit_transform(products['user_products']), columns=[f'prod_{item}' for item in mlb.classes_], index=products.index )
为什么你的循环方法慢?
你之前用的嵌套循环+ix赋值(注意ix已经被Pandas弃用,推荐用loc/iloc),本质是逐元素修改DataFrame——每次赋值都会触发DataFrame的内存重新分配和索引更新,大数据集下这种操作的开销会被无限放大。而上面的方法都是批量处理,底层用C语言实现,跳过了Python循环的额外开销,速度提升非常明显。
额外小技巧
- 如果原数据有缺失值,
stack()会自动忽略,get_dummies()和MultiLabelBinarizer也会自动处理,没出现的产品列默认是0; - 可以通过
get_dummies(prefix='prod')直接给列加前缀,不用手动拼接字符串; - 如果需要把结果填充0(比如原行没有的产品列),可以用
fillna(0)确保所有值都是0或1。
内容的提问来源于stack exchange,提问作者Subhanandh
相关产品推荐
相关产品推荐

