python pandas常用方法 pandas常用方法详细解析
本教程详细讲解了如何在Pandas中对数据排序连续出现的相同值进行分组,并在此基础上计算指定列的聚合统计量,例如顶点。通过结合使用shift()、ne()和cumsum()函数创建动态分组键,再配合groupby()和transform()方法,实现精确地对连续数据块进行分析,避免了传统分区方式的拥挤。1. 问题背景:传统分组的局限性
在数据分析中,我们经常需要对数据进行分组聚合。Pandas的groupby()函数是实现这一目标的核心工具。然而,当需求是针对列中“连续出现”的相同值进行分组时,传统的df .groupby('column_name') 方法可能无法满足要求。这是因为传统groupby 将所有具有相同值的行聚合在一起,而不管它们在原始数据源的位置是否连续。
例如,考虑以下数据集:import pandas as pddata = { 'Fruits': ['Apple', 'Apple', 'Banana', 'Orange', 'Apple', 'Apple'], 'Price': [20, 30, 50, 170, 55, 90]}df = pd.DataFrame(data)print(df) 登录后复制
输出: Fruits Price0 Apple 201 Apple 302 香蕉 503 Orange 1704 Apple 555 Apple 90登录后复制
我们的目标是计算每组连续相同水果的最高价格。具体来说,我们第一组连续的“苹果”(索引0,1)的最大价格是30,而第二组连续的“苹果”(索引4,5)的最大价格是90。如果直接使用df.groupby('Fruits')['Price'].max(),结果会是所有“Apple”中的顶峰90,这不符合按连续块分组的要求。2. 核心解决方案:动态分组键的构建
要解决这个问题,需要我们有一个机制来为每个时期连续的相同值生成一个唯一的组标识符。Pandas提供了强大的工具组合来实现这一点:shift()、ne()(或!=)和cumsum()。2.1步骤一:识别连续块的边界
首先,我们需要识别出连续块开始的位置。这可以通过比较当前行的值与上一行的值来实现。如果不一致,则意味着一个新的连续块开始了。
# 比较当前行与上一行'Fruits'列的值是否不符合# df.Fruits.shift() 粘贴 'Fruits' 上一级移动行,之前等于NaN# df.Fruits.ne(...) 继续于 df.Fruits != ...new_block_start = df.Fruits.ne(df.Fruits.shift())print(new_block_start)登录后复制
输出:0 True # 'Apple'与NaN不符合,视为新块开始1 False # 'Apple'与'Apple'则2 True # 'Banana'与'Apple'不符合,新块开始3 True # 'Orange'与'Banana'不符合,新块开始4 True # 'Apple'与'Orange'不一致,新块开始5 False # 'Apple'与'Apple'恰好Name:Fruits, dtype: bool登录后复制
这个布尔序列准确地标记了每个新连续块的起始位置。2.2步骤二:生成唯一的组ID
有了新块的起始标记,我们可以使用cumsum()(求和)来唯一生成的组ID。cumsum()把True视为1,False视为0,并累进行加。一旦遇到一个True(即新块开始),累加值就会增加1,从而为该连续块分配一个唯一的ID。grp = df.Fruits.ne(df.Fruits.shift()).cumsum()print(grp)登录后复制
输出:0 11 12 23 34 45 4Name:Fruits, dtype: int64登录后复制
现在,我们得到了一个完美的组ID序列:索引0和1(连续的'苹果')被分到组1。索引2('香蕉')被分到组2。索引3('橙色')被分到组3。索引4和5(连续的'苹果')被分到组4。
每个连续的相同水果类型都拥有一个独特的组ID。3. 应用聚合操作:groupby()与transform()
有了这个动态生成的分组键grp,我们就可以使用groupby()进行分组聚合了。关键在于使用transform('max')而不是agg('max')。groupby(grp):根据我们刚刚创建的grp系列进行分组。['Price']:选择我们要计算顶部的列。transform('max'):是核心。与agg('max')不同,transform() 会在每个组内执行指定的操作(这里是求顶层),把结果“广播”回原始DataFrame的对应行,保持原有的索引和形状。这意味着,如果一个组内有N行,transform就会返回N个相同的顶端,每个对应组内的一行。
# 完整的解决方案代码grp = df.Fruits.ne(df.Fruits.shift()).cumsum()df['Max'] = df.groupby(grp)['Price'].transform('max')print(df)登录后复制
最终输出:Fruits Price Max0 Apple 20 301 Apple 30 302 Banana 50 503 Orange 170 1704 Apple 55 905 Apple 90 90登录后复制
结果完全符合我们的预期:第一组连续的“苹果”的顶峰是30,第二组连续的“苹果”的顶峰是90。其他水果也分别计算了其连续块内的顶峰(由于它们是单行块,顶顶就是其自身价格)。4. 拓展与注意事项通用性:这种技术不仅限于计算顶层。你可以将transform('max')替换为transform('min')、transform('mean')、transform('sum')或任何其他聚合函数,以计算连续块内的其他统计量。应用场景:时间序列分析:识别连续几天上涨/下跌的股票价格,并计算其最大增量。数据清洗:标记或处理连续出现的重复值特征工程:为机器学习模型创建基于连续事件的特征。性能考量:Pandas的groupby()和transform()是高度优化的C实现,对于大型数据集通常表现出良好的性能。欠值处理:shift()操作会在第一行引入NaN。ne()函数能够正确处理NaN与非NaN的(NaN != value通常为True,NaN != NaN通常为True,请勿使用pd.isna().ne(pd.isna().shift()) 这样的方式)。在实际应用中,如果你的分区列中存在 NaN,可能需要额外考虑如何处理它们(例如,使用 fillna() 总结
通过巧妙地结合使用shift()、ne()和cumsum()来创建动态分组键,并配合groupby()和transform()方法,Pandas能够并高效准确地实现对数据块连续相同值块的聚合操作。这种方法比传统的循环或简单的groupby提高效率和灵活性,是处理复杂分组聚合需求时的强大工具。
以上就是Pandas技巧:高效处理连续相同值块并计算的详细,更多请关注聚合统计哥通网其他相关文章!