关于Pandas中df.apply()底层逻辑及DataFrame排序的技术咨询
嘿,我来帮你搞定这两个问题——先解决你遇到的按tip_pct排序的小麻烦,再好好唠唠df.apply()和groupby()结合的底层逻辑,这样你能把整个流程摸得透透的~
一、按
tip_pct排序的正确姿势&常见坑 首先,Pandas里专门用来按列值排序的方法是sort_values(),新手容易和按索引排序的sort_index()搞混,咱们先看正确的操作:
基础排序代码
# 按tip_pct升序排序(默认就是升序) tips_sorted_asc = tips.sort_values(by='tip_pct') # 按tip_pct降序排序,只需要加ascending=False tips_sorted_desc = tips.sort_values(by='tip_pct', ascending=False) # 如果想重置排序后的索引(避免原索引混乱),加ignore_index=True tips_sorted_reset = tips.sort_values(by='tip_pct', ignore_index=True)
你可能踩的几个坑
- 忘记赋值或滥用inplace:Pandas的排序方法默认返回新的DataFrame,不会修改原数据。如果你直接写
tips.sort_values(by='tip_pct'),原tips是不会变的,要么把结果赋值给新变量,要么用inplace=True(不过不推荐后者,会直接修改原数据,调试起来麻烦) - 混淆sort_values和sort_index:
sort_index()是按行索引排序的,不是按列值,别搞反了! - 缺失值处理:如果你的数据里有NaN,默认会被排到最后,要是想把NaN放前面,可以加
na_position='first'参数
二、
df.apply()和groupby()结合的底层逻辑 咱们拆成两部分讲,先搞懂单独的apply(),再看和groupby()搭配的流程:
单独的df.apply():逐行/逐列的循环处理
apply()本质上是循环遍历DataFrame的每一行或每一列,把每一行/列(以Series的形式)传入你定义的函数,最后把所有结果收集起来。
- 默认是按列处理(
axis=0),如果要逐行处理,加axis=1 - 它的优点是灵活性极高,能处理各种复杂逻辑,但缺点是速度不如Pandas的向量化操作(比如直接用
tips['total_bill'] + tips['tip']就比用apply()逐行加要快得多)
举个简单例子,逐行计算总账单+小费的金额:
def calculate_total(row): return row['total_bill'] + row['tip'] tips['total_with_tip'] = tips.apply(calculate_total, axis=1)
和groupby()结合:分组→逐组处理→合并结果
当你用tips.groupby('day').apply(your_func)时,底层走这三步:
- 拆分数据:根据分组键(比如这里的
day),把原DataFrame拆成多个子DataFrame,每个子DataFrame对应一个分组(比如周日的所有数据、周六的所有数据) - 逐组处理:把每个子DataFrame作为参数传入你写的
your_func函数,函数可以对这个子DataFrame做任何操作——计算统计量、排序、甚至生成新的DataFrame - 合并结果:把每个分组的处理结果合并成最终的输出,合并方式取决于你的函数返回值:
- 如果函数返回标量(比如一个数字),结果是一个Series,索引是分组键
- 如果函数返回Series,结果是一个DataFrame,索引是分组键+原Series的索引
- 如果函数返回DataFrame,结果会把所有子DataFrame按行拼接起来
比如用你的数据集,按day分组后计算每个分组的tip_pct均值和最大值:
import pandas as pd def get_group_stats(group_df): return pd.Series({ 'tip_pct_avg': group_df['tip_pct'].mean(), 'tip_pct_max': group_df['tip_pct'].max() }) day_tip_stats = tips.groupby('day').apply(get_group_stats)
这里每个分组的子DataFrame被传入get_group_stats,计算后返回一个Series,最后合并成一个以day为索引的统计DataFrame
最后提个小建议:如果你的需求能用Pandas内置的聚合方法(比如agg()、transform())实现,优先用这些方法,因为它们是向量化操作,速度比apply()快很多;只有当逻辑特别复杂,内置方法搞不定的时候,再用apply()~
内容的提问来源于stack exchange,提问作者Mukerong
相关产品推荐
相关产品推荐

