ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Pandas v0.16.2 版本发布详解:DataFrame.pipe 管道方法、性能优化与批量 Bug 修复

Pandas v0.16.2 版本发布详解:DataFrame.pipe 管道方法、性能优化与批量 Bug 修复 Pandas v0.16.2 版本发布详解DataFrame.pipe 管道方法、性能优化与批量 Bug 修复【免费下载链接】pandasFlexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more项目地址: https://gitcode.com/gh_mirrors/pa/pandas本文基于 pandas 仓库中的 v0.16.2 发布说明 撰写。pandas 0.16.2 是 2015 年 6 月 12 日发布的 0.16.1 次要 Bug 修复版本其最重要的贡献是引入影响深远的DataFrame.pipe管道式方法为 pandas 后续版本中的方法链method chaining编程范式奠定了基础。读完本文你将掌握pipe的设计动机、两种调用形式及其在 DataFrame、GroupBy、Resampler、Rolling 等对象上的统一用法并了解该版本在 API 变更、性能优化与数十项 Bug 修复上的全貌。一、版本概览一次小版本、大影响的发布根据 doc/source/whatsnew/v0.16.2.rstpandas 0.16.2 是一个从 0.16.1 出发的次要 Bug 修复版本在修复大量 Bug 的同时也带来了一些新特性、增强与性能改进。官方明确建议所有用户升级到该版本。该版本的两大亮点是新增DataFrame.pipe方法本文核心主题见下文第二节补充了如何在 pandas 中使用 numba 加速的文档对应仓库中的 doc/source/user_guide/enhancingperf.rst。发布说明还通过自动化的 contributors 机制.. contributors:: v0.16.1..v0.16.2列出了从 0.16.1 到 0.16.2 期间所有贡献者的名单。二、核心新特性DataFrame.pipe 管道方法2.1 动机嵌套函数调用的可读性危机pipe的引入是为了解决 pandas 用户在做多步数据处理时常见的嵌套调用可读性问题。考虑如下场景df是一个 DataFramef、g、h是三个接收 DataFrame、返回 DataFrame的函数# df 是一个 DataFrame # f、g、h 分别是接收并返回 DataFrame 的函数 f(g(h(df), arg11), arg22, arg33)这段代码有三个明显的缺陷逻辑流向与阅读方向相反数据实际从最内层的h(df)开始流动但阅读时必须从最外层f(...)开始逐层向内解析逻辑是从内向外的与代码书写顺序从外向内完全相反函数名与参数分离arg11属于g却写在靠近f的位置无法一眼看出每个参数属于哪个函数修改调用顺序时极易出错调整一步处理就要重新整理整段括号。2.2 基本用法让逻辑自上而下流动pipe将上述嵌套调用改写为自上而下、线性展开的链式调用( df.pipe(h) .pipe(g, arg11) .pipe(f, arg22, arg33) )改写之后代码顺序与逻辑流向一致都是从顶部到底部关键字参数紧邻其所属函数arg11跟在g旁边整体可读性显著提升也更容易逐行注释、调试和复用。pipe的名字与设计灵感来源于Unix 管道将文本流经多个进程并参考了 R 语言生态中dplyr和magrittr引入的%%管道运算符对应 issue #10129。2.3 进阶用法数据不在首参数时使用(函数, 关键字)元组上面的例子中f、g、h都约定把 DataFrame 作为第一个位置参数接收。但实际业务中很多库的函数签名并非如此——例如 statsmodels 的sm.ols(formula, data)数据位于第二个位置参数。pipe对此提供了元组形式(function, keyword)其中keyword是接收数据的那个参数名。以下示例完整展示了这种用法数据文件见 doc/data/baseball.csvimport statsmodels.formula.api as sm bb pd.read_csv(data/baseball.csv, index_colid) # sm.ols 的签名是 (formula, data)数据在第二个位置 ( bb.query(h 0) .assign(ln_hlambda df: np.log(df.h)) .pipe((sm.ols, data), hr ~ ln_h year g C(lg)) .fit() .summary() )这段链式调用完成了过滤有安打h 0的记录 → 新增取对数后的ln_h列 → 交给 statsmodels 拟合 OLS 回归 → 拟合 → 输出摘要的完整流程。(sm.ols, data)告诉pipe把当前的 DataFrame 以data...关键字形式传给sm.ols而hr ~ ln_h year g C(lg)作为第一个位置参数公式传入。输出即为标准的 OLS 回归结果摘要statsmodels.iolib.summary.Summary。2.4 源码级原理pipe 在 pandas 中的统一实现pipe并非一次性散落在各对象上的方法而是通过一个统一的底层函数实现。在当前仓库的 pandas/core/common.py 中可以找到其核心逻辑见 pandas/core/common.py#L484-L540def pipe(obj, func, *args, **kwargs): if isinstance(func, tuple): # 元组形式(callable, data_keyword) func_, target func if target in kwargs: msg f{target} is both the pipe target and a keyword argument raise ValueError(msg) kwargs[target] obj return func_(*args, **kwargs) else: # 普通形式obj 作为第一个位置参数传入 return func(obj, *args, **kwargs)这段实现清晰揭示了两个关键设计普通函数形式func(obj, *args, **kwargs)即对象总是作为第一个位置参数被注入元组形式把第二个元素target当作关键字名执行kwargs[target] obj后再调用。实现中还包含一处保护性检查若调用者同时在关键字参数里传入了与target同名的参数会抛出ValueError提示该名称既是 pipe 的目标又是关键字参数避免歧义。从当前仓库源码看pipe的接入点覆盖了 pandas 几乎所有容器型对象它们全部委托给common.pipeDataFrame / Series定义在 pandas/core/generic.py#L6054-L6160其实现为return common.pipe(self.copy(deepFalse), func, *args, **kwargs)即传入对象的浅拷贝视图docstring 中给出了联邦税 → 州税 → 国民保险三阶段扣税的完整示例展示嵌套写法与pipe写法的对照GroupBy定义在 pandas/core/groupby/groupby.py#L456-L546实现为return com.pipe(self, func, *args, **kwargs)允许把整个 GroupBy 对象直接传入自定义函数例如df.groupby(A).pipe(lambda x: x.max() - x.min())一次求出各组极差Resampler定义在 pandas/core/resample.py#L251-L267Rolling / Expanding分别定义在 pandas/core/window/rolling.py 与 pandas/core/window/expanding.py。此外pipe的两个overload签名普通可调用对象与tuple[Callable, str]在类型标注层面也完整覆盖了两种调用形式。可以说v0.16.2 引入的这个方法在后来的版本中被体系化地推广到了整个 pandas 对象家族成为方法链编程的基石。更多用法可参考 doc/source/user_guide/basics.rst 中的管道相关章节。三、其他增强除了pipe之外该版本还有以下增强对应发布说明中的 Other enhancements 小节rsplit加入 Index/Series 的字符串方法族issue #10303Series.str.rsplit/Index.str.rsplit支持从字符串右侧开始按分隔符切分。从当前仓库 pandas/core/strings/accessor.py 的文档可以看出它与split的区别在不指定n时两者输出相同指定n后行为分道扬镳——例如s.str.split(n2)与s.str.rsplit(n2)对同一字符串会产出不同的切分结果rsplit(n2)适合从右往左取固定段数如按/从 URL 右侧切出最后一段。同时rsplit也支持expandTrue展开为 DataFrame/MultiIndex且n是切分次数的上限而非保证的列数列数不足时用NaN填充。移除 DataFrame HTML 表示中的硬编码尺寸上限issue #10231在 IPython notebook要求 IPython v3.0 及以上中不再由 pandas 强行限制大 DataFrame 的显示尺寸交还给 IPython 自身处理消除了大表格在 notebook 中出现的重复滚动条。notebook 自带toggle output scrolling功能点击输出左侧区域可折叠超大帧也可以通过 pandas 选项定制 DataFrame 的展示方式详见 doc/source/user_guide/options.rst。DataFrame.quantile的axis参数扩展issue #9543axis现在除了接受0/1之外还接受字符串形式的index与columns与 pandas 全局统一的 axis 命名约定保持一致。四、API 变更本版本的 API 变更仅有一项但属于行为收紧性质Holiday构造器参数互斥检查issue #10217pandas.tseries.holiday.Holiday此前允许在构造时同时传入offset和observance但会返回错误的结果从本版本起两者同时使用时直接抛出NotImplementedError。相关类的定义可参考当前仓库的 pandas/tseries/holiday.py。这一变更体现了 pandas 一贯的 API 策略与其静默返回错误结果不如在构造阶段显式报错让用户及早发现参数误用。五、性能改进该版本包含两项性能优化Series.resample性能提升针对dtypedatetime64[ns]的序列重采样做了优化issue #7754str.split性能提升expandTrue时的字符串切分路径得到加速issue #10081。六、Bug 修复全览v0.16.2 修复了大量 Bug覆盖 IO、时间序列、Categorical、GroupBy、绘图、算术运算与文本处理等多个模块。以下按类别整理issue 编号与发布说明一致6.1 IO 与文件读写HDFStore.select会意外修改传入的 columns 列表#7212read_csv在enginepython下会把含指数但无小数点的字符串如1e3解析为int而非float#9565read_csv在解析空 DataFrame 时未正确设置索引名#10184read_csv的date_parser若返回非[ns]精度的datetime64数组会出错#10245DataFrame.to_hdf()对非字符串列名报出看似无关的错误现改为显式禁止#9057read_hdf无法传递auto_close参数#9327read_hdf无法使用已打开的 store#10330to_hdf/HDFStore未校验 complib 压缩库选择的合法性#4582、#8874to_csv在 datetime 含小数部分时忽略date_format#10209MySQL 接口无法处理纯数字的表名/列名#10255。6.2 时间序列与索引Timestamp的microsecond、quarter、dayofyear、week、daysinmonth属性返回np.int而非内置int#10050NaT访问daysinmonth、dayofweek属性时抛AttributeError#10096多平台下使用dateutil获取时区数据失败#9059、#8639、#9663、#10121混合频率 datetime 的显示精度问题#10170DatetimeIndex/TimedeltaIndex在进行 timedelta 算术运算后丢失名称#9926TimedeltaIndex切片可能重置 freq#10292infer_freq推断出to_offset不支持的 WOM-5XXX 规则#9425。6.3 Categorical 与 GroupBygroupby.apply聚合 Categorical 时未保留 categories#10138GroupBy.get_group按多个键分组且其中一个是 Categorical 时出错#10132GroupBy.get_group在分组键含NaT时抛ValueError#6992Categorical的 repr 在 Python 3 下与display.widthNone组合时出错#10087Categorical.remove_categories在底层为浮点 dtype 时移除NaN类别会抛ValueError#10156Index.union传入 array-like 参数时抛AttributeError#10149Indexrepr 在max_seq_itemsNone设置下的问题#10182。6.4 构造、算术与统计DataFrame从嵌套 dict 构造时处理datetime64出错#10160Series从 dict 构造时datetime64键处理出错#9456Series算术方法可能错误地持有名称#10068Series.align指定fill_value时重置name#10067mean()中整型 dtype 可能溢出#10172DataFrame.quantile对传入非法 axis 的校验问题#9543部分 nan 相关函数返回 dtype 不一致#10251Series.hist在输入为单行 Series 时抛错#10214setitem时类型提升被应用到整个 block#10280合并consolidating时缓存更新问题#10264to_json对某些 orient 与CategoricalIndex组合会段错误#10317DataFrame.to_json处理混合数据类型出错#10289Panel.from_dict指定 dtype 时未生效#10058Panel.apply结果为 ndim0 时出错#10332空 DataFrame 相加后.equals空 DataFrame 失败#10181掩码空 DataFrame 的处理#10126。6.5 绘图与稀疏数据Series.plot(labelLABEL)未正确设置标签#10119plot未默认继承 matplotlib 的axes.grid设置#9792SparseSeries.abs重置name#10241SparseSeries构造器忽略输入数据的 name#10258。6.6 小结这批修复集中体现了 pandas 在数据一致性名称保留、dtype 一致、类别保留、边界输入空数据、单行、NaT、NaN类别以及跨库兼容MySQL、dateutil、IPython、statsmodels三个方向上的持续打磨也解释了为何发布说明要求用户升级。七、总结与参考pandas 0.16.2 虽然定位为次要 Bug 修复版本但其引入的DataFrame.pipe为 pandas 的方法链编程风格打开了大门(func, keyword)元组形式的灵活设计至今仍在使用。从当前仓库的 pandas/core/common.py 可以看出这套机制已被统一扩展至 DataFrame、Series、GroupBy、Resampler、Rolling、Expanding 等全部主要对象。如需进一步阅读pipe的使用文档doc/source/user_guide/basics.rstnumba 加速文档doc/source/user_guide/enhancingperf.rst显示选项配置doc/source/user_guide/options.rstpipe核心实现pandas/core/common.py、pandas/core/generic.py、pandas/core/groupby/groupby.py字符串方法实现pandas/core/strings/accessor.py节假日 APIpandas/tseries/holiday.py【免费下载链接】pandasFlexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more项目地址: https://gitcode.com/gh_mirrors/pa/pandas创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进