Pandas groupby.sum()使用异常:小数据正常大数据结果不符
问题分析与解决方案
首先,你的问题根源在于**new_df["SUM"] = new_df.groupby(["ID"]).sum().reset_index(drop=True)**这一行:当你对ID分组求和后,得到的结果行数是唯一ID的数量,而new_df是explode后的多行数据(每个ID对应多行),直接赋值时Pandas会按索引对齐,这就导致大部分行的SUM值要么是NaN,要么被错误填充。小样本因为数据量小、索引刚好巧合匹配才没暴露问题,大数据量下索引对齐的矛盾就完全显现了。
修正步骤
我们需要用groupby.transform('sum')来替代原有的求和方式,transform会将组内的求和结果广播到该组的每一行,保证结果和原数据行数一致,完美解决索引对齐问题。下面是修正后的完整代码:
import pandas as pd df = pd.read_excel(r"D:\Tesina\Proteoma Humano\Tablas\uno - copia.xlsx") # df = pd.DataFrame({'ID': ['C9JLR9','O95391', 'P05114',"P14866"], 'SEQ': ['1..100,182..250,329..417,490..583', '1..100,206..254,493..586', '1..100', "1..100,284..378" ]}) # 替换分隔符并拆分SEQ df["SEQ"] = df["SEQ"].replace("\.\."," ", regex=True) new_df = df.assign(SEQ=df.SEQ.str.split(',')).explode('SEQ') # 计算delta值,去掉冗余循环,一次计算完成 def calculate_delta(x): parts = x.split() start = int(parts[0]) end = int(parts[1]) return (end + 1) - start if start != 1 else (end + 1) new_df['delta'] = new_df['SEQ'].apply(calculate_delta) # 关键修正:用transform计算组内求和,保证和原数据行数一致 new_df["SUM"] = new_df.groupby(["ID"])['delta'].transform('sum') # 最后合并SEQ的逻辑保持不变 df2 = new_df.groupby(["ID","SUM"], sort=False)["SEQ"].apply(lambda x: ','.join(x.astype(str))).reset_index(name="SEQ")
额外优化点
- 去掉了原代码中的
for index, row in df.iterrows()循环:这个循环其实是重复对整个new_df['delta']赋值,完全没必要,直接用apply一次计算即可,效率更高。 - 明确指定求和的列是
delta:原代码中groupby.sum()会对所有数值列求和,虽然这里只有delta,但明确指定列更清晰,避免后续添加列时出错。
这样修改后,不管是小样本还是10471行的大数据,SUM值都会准确对应每个ID的delta总和,且保持原数据行数不变。
内容的提问来源于stack exchange,提问作者JuanMacD
相关产品推荐
相关产品推荐

