Pandas DataFrame多组分组的唯一标识符分配及性能优化问询
高效实现Pandas按分组批量分配唯一标识符
问题场景
给定Pandas DataFrame如下:
import pandas as pd df = pd.DataFrame({'A':[1,2,3,4,6,3,7,3,2,11,13,10,1,5],'B':[1,1,1,2,2,2,2,3,3,3,3,3,4,4], 'C':[1,1,1,1,1,1,1,2,2,2,2,2,3,3]})
需求是为B列的分组按从上到下的顺序,每两组分配一个唯一标识符(例如B=1、2对应D=1,B=3、4对应D=2)。
原实现方式通过循环遍历分组切片并逐次赋值,在7万行数据场景下效率极低,原代码如下:
b_unique_cnt = df['B'].nunique() the_list = list(range(1, b_unique_cnt+1)) slice_size = 2 list_of_slices = zip(*(iter(the_list),) * slice_size) counter = 1 df['D'] = -1 for i in list_of_slices: df.loc[df['B'].isin(i), 'D'] = counter counter = counter + 1 df.head(15)
原方法效率瓶颈分析
原方法通过循环生成分组切片,每次调用isin和loc修改DataFrame列值,这种操作会反复触发Pandas的索引查找与数据更新,在数据量较大时,多次的切片和赋值会带来显著的性能开销,导致处理速度缓慢。
高效优化方案
方案1:向量化操作(最优性能)
利用pd.factorize对B列按出现顺序生成编码,再通过整数除法批量生成分组标识符,全程无循环,完全向量化:
# 对B列按首次出现顺序生成连续编码(从0开始) b_codes, _ = pd.factorize(df['B'], sort=False) slice_size = 2 # 整数除法后加1,让标识符从1开始 df['D'] = (b_codes // slice_size) + 1
原理:pd.factorize会按B列元素第一次出现的顺序生成连续整数编码(如B=1→0、B=2→1、B=3→2、B=4→3),通过// slice_size将每2个编码归为一组,最后加1让标识符从1起始,完美匹配需求。
方案2:映射字典法(逻辑清晰)
先提取B列唯一值的出现顺序,创建映射字典后一次性完成赋值:
slice_size = 2 # 获取B列唯一值的出现顺序(保证从上到下) b_unique_order = df['B'].unique() # 构建B值到分组标识符的映射 group_map = {b_val: (idx // slice_size) + 1 for idx, b_val in enumerate(b_unique_order)} # 批量映射生成D列 df['D'] = df['B'].map(group_map)
原理:先拿到B列唯一值的原始顺序,遍历每个值并根据其索引位置计算对应的分组号,最后用map方法一次性完成整列的映射赋值,避免循环操作。
验证结果
两种方案生成的D列结果一致:
0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 2 8 2 9 2 10 2 11 2 12 2 13 2 Name: D, dtype: int64
内容的提问来源于stack exchange,提问作者Arjun Chaudhary
相关产品推荐
相关产品推荐

