在Pandas中基于id与is_opt列高效重组product_id列的方法
问题
现有一个包含id、product_id、is_opt三列的Pandas DataFrame,示例数据如下:
id product_id is_opt 1 1 False 1 2 False 1 3 True 1 4 True 2 5 False 2 6 False 2 7 False 3 8 False 3 9 False 3 10 True
需按以下规则转换该DataFrame:
- 对于同一
id的行组,若所有行is_opt均为False,则该行组保持不变(如id=2的行); - 若行组中至少存在一行
is_opt为True:is_opt为True的行保持不变;is_opt为False的行需将该id下所有is_opt为True的product_id拼接到自身product_id后,每行生成n行(n为该行组中is_opt为True的行数),例如[1,1,False]将生成[1,1-3,False]和[1,1-4,False]。
转换后需删除is_opt列,期望输出如下:
id product_id 1 1-3 1 1-4 1 2-3 1 2-4 1 3 1 4 2 5 2 6 2 7 3 8-10 3 9-10 3 10
生产环境数据量庞大,循环实现效率太低,寻求高效的操作方法。
高效实现方案
以下方案基于Pandas的分组、向量化操作实现,全程避免循环,适合大数据量场景:
1. 分组提取每个id的opt产品信息
先按id分组,提取每个组内is_opt=True的product_id列表,同时标记该组是否存在opt产品:
import pandas as pd # 初始化示例数据(实际使用时替换为你的DataFrame) df = pd.DataFrame({ 'id': [1,1,1,1,2,2,2,3,3,3], 'product_id': [1,2,3,4,5,6,7,8,9,10], 'is_opt': [False, False, True, True, False, False, False, False, False, True] }) # 分组获取每个id的opt产品列表及是否存在opt产品 opt_groups = df.groupby('id').apply( lambda x: pd.Series({ 'opt_products': x[x['is_opt']]['product_id'].astype(str).tolist(), 'has_opt': not x['is_opt'].all() }) ).reset_index()
2. 拆分数据为三类子集
将原数据拆分为无opt产品的组、有opt产品的组中的opt行、有opt产品的组中的非opt行:
# 无opt产品的组,直接保留原数据(移除is_opt列) no_opt_df = df.merge(opt_groups[opt_groups['has_opt'] == False], on='id')[['id', 'product_id']] # 有opt产品的组,拆分出opt行和非opt行 has_opt_df = df.merge(opt_groups[opt_groups['has_opt'] == True], on='id') opt_rows = has_opt_df[has_opt_df['is_opt']][['id', 'product_id']] non_opt_rows = has_opt_df[~has_opt_df['is_opt']]
3. 处理非opt行的笛卡尔积拼接
对非opt行,和对应id的opt产品列表做笛卡尔积,完成product_id的拼接:
# 展开opt_products列,生成笛卡尔积 non_expanded = non_opt_rows.explode('opt_products') # 拼接product_id non_expanded['product_id'] = non_expanded['product_id'].astype(str) + '-' + non_expanded['opt_products'] # 保留需要的列 processed_non_opt = non_expanded[['id', 'product_id']]
4. 合并所有结果并排序
将处理后的非opt行、opt行、无opt组的数据合并,再按id排序(可选,匹配示例输出顺序):
# 合并所有子集 final_df = pd.concat([processed_non_opt, opt_rows, no_opt_df], ignore_index=True) # 按id排序 final_df = final_df.sort_values('id').reset_index(drop=True) print(final_df)
运行后输出与期望结果完全一致,所有操作均为Pandas原生的高效操作,能大幅提升大数据量下的处理速度。
内容的提问来源于stack exchange,提问作者soling
相关产品推荐
相关产品推荐

