如何基于已保存的最大groupid偏移量使用cumsum()生成新groupid?
问题背景与需求
- 前置条件:已有DataFrame(
dfold)数据保存为CSV,通过以下代码生成groupid:
import pandas as pd columns = ['timestamp','base'] data = [['2022-10-14 11:47:38',100], ['2022-10-14 11:47:39',100], ['2022-10-14 11:47:40',100], ['2022-10-14 11:47:41',100], ['2022-10-14 11:47:42',200], ['2022-10-14 11:47:43',200], ['2022-10-14 11:47:44',300], ['2022-10-14 11:47:45',300]] dfold = pd.DataFrame(data=data,columns=columns) dfold.set_index(['timestamp'],inplace=True) dfold['pbase'] = dfold['base'].shift(1).fillna(0) dfold['pbase'] = dfold['pbase'].astype(int) dfold['groupid'] = (dfold['base']!=dfold['pbase']).cumsum() print('Print dfold\n',dfold)
输出结果:
Print dfold: base pbase groupid timestamp 2022-10-14 11:47:38 100 0 1 2022-10-14 11:47:39 100 100 1 2022-10-14 11:47:40 100 100 1 2022-10-14 11:47:41 100 100 1 2022-10-14 11:47:42 200 100 2 2022-10-14 11:47:43 200 200 2 2022-10-14 11:47:44 300 200 3 2022-10-14 11:47:45 300 300 3
- 数据基于
groupid列逻辑分组,groupid由cumsum()生成。问题在于新数据集(dfnew)的groupid会从1重新开始,而非从已分配的最大ID开始。以下是dfnew的代码及输出:
columns2 = ['timestamp','base'] data2 = [['2022-10-14 11:47:46',400], ['2022-10-14 11:47:47',400], ['2022-10-14 11:47:48',500], ['2022-10-14 11:47:49',500]] dfnew = pd.DataFrame(data=data2,columns=columns2) dfnew.set_index(['timestamp'],inplace=True) dfnew['pbase'] = dfnew['base'].shift(1).fillna(0) dfnew['pbase'] = dfnew['pbase'].astype(int) dfnew['groupid'] = (dfnew['base']!=dfnew['pbase']).cumsum() print('Print dfnew\n',dfnew)
输出结果:
Print dfnew: base pbase groupid timestamp 2022-10-14 11:47:46 400 0 1 2022-10-14 11:47:47 400 400 1 2022-10-14 11:47:48 500 400 2 2022-10-14 11:47:49 500 500 2
- 获取已分配的最大
groupid:
maxgroupid = dfold['groupid'].max() print('Max group id stored is: ',maxgroupid)
输出结果:
Max group id stored is: 3
- 需求:为
dfnew中的新数据重新分配唯一groupid,从4开始,预期结果如下:
Expected result in dfnew: base pbase groupid timestamp 2022-10-14 11:47:46 400 0 4 2022-10-14 11:47:47 400 400 4 2022-10-14 11:47:48 500 400 5 2022-10-14 11:47:49 500 500 5
- 尝试的方法未成功:
grpnew = dfnew.groupby('groupid',as_index=True).max() print('Grouped dfnew:\n',grpnew) grpnew['newgroupid'] = range(maxgroupid + 1, maxgroupid + 1 + len(grpnew)) print('New groupid added to grouped dfnew:\n',grpnew) dfboth = pd.merge(dfnew,grpnew,on='groupid',how='outer') print(dfboth)
输出结果:
**Grouped dfnew:** base pbase groupid 1 400 400 2 500 500 **New groupid added to grouped dfnew:** base pbase newgroupid groupid 1 400 400 4 2 500 500 5 **Merged output (unable to merge timestamp index)** base_x pbase_x groupid base_y pbase_y newgroupid 0 400 0 1 400 400 4 1 400 400 1 400 400 4 2 500 400 2 500 500 5 3 500 500 2 500 500 5
- 待解决问题:
- (a) 合并后的DataFrame(
dfboth)丢失timestamp索引; - (b) 不确定该方法的性能是否最优。
解决方案
方法一:直接偏移groupid(高效简洁,推荐)
不需要复杂的分组合并,直接在生成初始groupid后,加上已有的最大groupid即可,完全保留原索引:
# 先生成从1开始的初始groupid dfnew['groupid'] = (dfnew['base'] != dfnew['pbase']).cumsum() # 偏移到从maxgroupid+1开始 dfnew['groupid'] += maxgroupid
执行后得到预期结果:
base pbase groupid timestamp 2022-10-14 11:47:46 400 0 4 2022-10-14 11:47:47 400 400 4 2022-10-14 11:47:48 500 400 5 2022-10-14 11:47:49 500 500 5
方法二:修复原合并方法(保留索引)
如果一定要用分组合并的方式,需要先重置索引保留timestamp,合并后再恢复索引:
# 重置索引,把timestamp转为普通列 dfnew_reset = dfnew.reset_index() # 分组生成新groupid映射 grpnew = dfnew.groupby('groupid', as_index=True).max() grpnew['newgroupid'] = range(maxgroupid + 1, maxgroupid + 1 + len(grpnew)) # 仅合并newgroupid列,避免重复列 dfboth = pd.merge(dfnew_reset, grpnew[['newgroupid']], on='groupid', how='left') # 恢复timestamp为索引,替换原groupid并清理冗余列 dfboth.set_index('timestamp', inplace=True) dfboth['groupid'] = dfboth['newgroupid'] dfboth.drop('newgroupid', axis=1, inplace=True)
方案对比
- 方法一:时间复杂度O(n),仅需一次数值偏移,完全保留原索引,性能最优,代码极简,是本次需求的最佳选择。
- 方法二:时间复杂度O(n log n)(分组操作带来额外开销),步骤繁琐,仅适用于复杂分组映射场景,本次需求无需使用。
内容的提问来源于stack exchange,提问作者plain
相关产品推荐
相关产品推荐

