当前位置: 首页 > web >正文

Pandas 高效数据处理:apply、向量化与分组

Pandas 高效数据处理:apply、向量化与分组进阶实战(附代码示例)

  • 适用人群: 想系统掌握 Pandas 自定义计算、性能优化、分组聚合与转换的同学
  • 核心要点: apply 的行列处理、真正向量化 vs 伪向量化、GroupBy 的聚合/转换/apply 全景案例

一、为什么需要这些技术

  • apply: 用自定义函数批量处理 Series/DataFrame/GroupBy,替代显式 for 循环。
  • 向量化: 利用底层 C/NumPy 实现的批处理(极快);np.vectorize 提供向量化接口但本质仍是循环(伪向量化)。
  • 分组进阶: 统计、对齐转换(transform 类似 SQL 窗口函数)、组级过滤、自定义 apply。

二、apply 入门与典型用法

1)对 Series:逐元素

“”"
apply函数是pandas中自由度(自定义)最高的函数之一,用来对series、dataframe或者分组对象应用自定义函数,他的核心行为是:
1:对series,逐个元素进行处理(输入单个值,输出单个值)
“”"

import pandas as pdprint("----------对series中使用apply--------------")
def my_fun1(x):return x ** 2s = pd.Series([1,2,3,4])
r1 = s.apply(my_fun1)
  • 也可传参:
def my_fun2(x, e):return x ** er2 = s.apply(my_fun2, e=3)

2)对 DataFrame:按行或按列传入 Series

print("----------对dataframe中使用apply--------------")
df = pd.DataFrame({'a':[10,20,30], 'b': [20,30,40]})
def my_fun3(x):print(f"x的内容:\n{x}")print(f"x的类型:{type(x)}")df.apply(my_fun3, axis=1)   # axis=1 按“行”传入 Series
  • 误区提示:函数签名需与传入对象匹配(行/列 Series),否则会报参不匹配错误。
df = pd.read_csv("data/titanic_train.csv")
def count_missing(vec):return pd.isnull(vec).sum()
def prop_missing(vec):return pd.isnull(vec).sum() / vec.size
def prop_complete(vec):return 1-prop_missing(vec)print(df.apply(count_missing))             # 按列
print(df.apply(prop_missing))
print(df.apply(prop_complete))
print(df.apply(count_missing, axis=1))     # 按行

要点:

  • axis=0(默认)按列;axis=1 按行。
  • 行列粒度输出分别用于字段健康度与行级质量检查。

三、真正向量化 vs 伪向量化(np.vectorize)

教程总结要点如下:
“”"
真正的向量化:底层C/NumPy实现,性能极高,语法简洁,广泛覆盖数学/统计/字符串/日期等。
np.vectorize:伪向量化,内部仍是python循环,接口友好但性能远逊真·向量化。
apply:最灵活,但性能最低。
性能:向量化函数>伪向量化函数>apply(自定义函数)
“”"

- 真·向量化示例(列运算、标量运算、NumPy 通用函数):- `df['C'] = df['A'] + df['B']`- `df['D'] = df['A'] * 10`- `df['E'] = np.log(df['A'])`- `np.vectorize` 适用场景:- 自定义标量函数、多分支复杂逻辑,或多参数且需固定部分参数时。- 注意:它不是性能优化的“银弹”,只是让写法像向量化。实践建议:
- 能用真·向量化就不要用 apply/np.vectorize。
- 需要强自定义且无等价向量化方案时,再考虑 `np.vectorize` 或 `apply`。---## 四、GroupBy 分组进阶:聚合、转换、应用### 1)概念全景
"""
分组:groupby();按列/函数/索引分组
聚合:agg()/aggregate()
转换:transform() 返回与原始数据同大小(组内对齐)
过滤:filter() 基于组属性筛组
应用:apply() 对组DataFrame做任意处理
"""

2)使用 Gapminder 数据做统计实践

df = pd.read_csv("data/gapminder.tsv", sep="\t")
df.groupby("year")
df.groupby(["year", "continent"])
print(df.groupby("year").lifeExp.mean())
print(df.groupby("year")['lifeExp'].mean())
  • 常用描述统计:
print(df.groupby("continent").lifeExp.count())
print(df.groupby("continent").lifeExp.describe())
print(df.groupby("continent").lifeExp.agg(lambda x: np.mean(x)))
  • 结合全局值做组内“差值”分析(传参 + 自定义聚合):
global_lifeExp_mean = df.lifeExp.mean()
def my_mean_diff(col, lifeExp_mean):return col.mean() - lifeExp_mean
print(df.groupby("continent").lifeExp.agg(my_mean_diff, lifeExp_mean=global_lifeExp_mean))
  • 一次性对不同列做不同聚合并改列名:
print(df.groupby("year").agg({'lifeExp':'mean','pop':'max','gdpPercap':'min'
}).rename(columns={'lifeExp':'平均寿命', 'pop':'最大人口', 'gdpPercap':'人均最小GDP'}).reset_index())

3)转换 transform:组内对齐输出(窗口函数思维)

计算 Z-Score(标准分数)并按年分组,结果与原数据等长、可直接对齐赋值:

def my_zscore(x):return (x - x.mean()) / x.std()
print(df.groupby('year').lifeExp.transform(my_zscore))

4)小案例:按性别组均值填充消费总额缺失值

tops_10_df = pd.read_csv("data/tips.csv").sample(n=10, random_state=20)
tops_10_df.loc[np.random.permutation(tops_10_df.index)[:4], 'total_bill'] = np.NaNdef my_fillna(x):return x.fillna(x.mean())r1 = tops_10_df.groupby('sex').total_bill.transform(my_fillna)
  • 思路:按 sex 分组 → 对每组 total_bill 用组均值填充 → transform 保持原长度,直接对齐回写到原列,避免 merge。

五、选型建议与最佳实践

  • 优先顺序(速度):真正向量化 > np.vectorize(伪) > apply
  • apply 何时用
    • 需要高度灵活的自定义逻辑,且难以映射为向量化表达式
    • 分组后的整组 DataFrame 级复杂处理
  • transform 常用场景
    • 需要与原表逐行对齐输出(标准化、组均值填充、组排名、比值偏差等)
  • 性能注意
    • 尽量减少 Python 层循环;多利用 Pandas/NumPy 内建函数与表达式
    • 多列多指标聚合用 agg(dict) 一次完成,减少多次扫描
  • 可读性
    • 分组链式写法建议 .groupby(...).agg(...).rename(...).reset_index(),用于清晰输出

六、可直接复用的模板片段

  • 组内 Z-Score 并对齐:
df['lifeExp_z'] = df.groupby('year')['lifeExp'].transform(lambda x: (x - x.mean())/x.std())
  • 多列多指标聚合:
out = df.groupby('year').agg({'lifeExp':'mean','pop':'max','gdpPercap':'min'
}).rename(columns={'lifeExp':'平均寿命','pop':'最大人口','gdpPercap':'人均最小GDP'}).reset_index()
  • 组均值缺失值填充:
df['total_bill'] = df.groupby('sex')['total_bill'].transform(lambda x: x.fillna(x.mean()))

七、结语

本文系统梳理了 Pandas 的 apply、向量化与分组进阶技巧,并通过 gapminder 与 tips 两个数据集展示了典型统计与缺失值处理套路。建议在项目中优先考虑“真·向量化 + groupby/transform”,在必须强自定义时再回退到 np.vectorizeapply

更新日期:2025年8月25日,后续会持续更新

http://www.xdnf.cn/news/18888.html

相关文章:

  • Android用Coil 3检查媒体资源是否有效,Kotlin
  • LeetCode 面试经典 150_双指针_验证回文串(25_125_C++_简单)(双指针)
  • 基于多通道同步分析的智能听诊系统应用程序
  • k8s数据存储
  • k8s-容器化部署论坛和商城服务(小白的“升级打怪”成长之路)
  • Rust Async 异步编程(六):Pin 和 Unpin
  • Python实现点云投影到直线、平面、柱面和球面
  • ComfyUI AI一键换装工作流无私分享
  • 《分布式系统跨服务数据一致性Bug深度复盘:从现象到本质的排查与破局》
  • 从“数据孤岛”到“业财融合”,外贸订单管理ERP重构一体化逻辑
  • 电气工程及其自动化的课程笔记
  • 接口自动化测试:测试用例也能自动生成
  • Vue3 + Golang Gin 实现客服实时聊天系统(WebSocket + Socket.IO 详解)
  • 【工具安装使用-Jetson】Jetson Orin Nano 刷机和踩坑总结
  • 从人工巡检到AI预警:智慧工地如何用技术重构施工安全体系
  • Flink 状态 RocksDBListState(写入时的Merge优化)
  • 《C++哈希表:高效数据存储与检索的核心技术》
  • 正则表达式 —— \s*
  • C# 相机内存复用(减少图像采集耗时)以及行数复用
  • HTB赛季8靶场 - Previous
  • 无障碍辅助模块|Highcharts引领可访问数据可视化的交流
  • 《李沐读论文》系列笔记:论文读写与研究方法【更新中】
  • 【每天一个知识点】大模型训推一体机
  • linux的conda配置与应用阶段的简单指令备注
  • Hadoop(四)
  • Rust爬虫实战:用reqwest+select打造高效网页抓取工具
  • HIVE创建UDF函数全流程
  • nowcoder刷题--反转链表
  • MCP 协议原理与系统架构详解—从 Server 配置到 Client 应用
  • SSM从入门到实战:3.1 SpringMVC框架概述与工作原理