ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

pandas PDEP-14 解读:pandas 3.0 默认字符串类型 “str“ 的设计、缺失值语义与迁移实践

pandas PDEP-14 解读:pandas 3.0 默认字符串类型 “str“ 的设计、缺失值语义与迁移实践 pandas PDEP-14 解读pandas 3.0 默认字符串类型 str 的设计、缺失值语义与迁移实践【免费下载链接】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 仓库中的 PDEP-14 设计文档web/pandas/pdeps/0014-string-dtype.md为核心结合当前仓库源码pandas/core/arrays/string_.py、pandas/core/config_init.py与测试用例pandas/tests/arrays/string_/test_string.py系统讲解 pandas 3.0 起默认启用专用字符串类型str的背景、命名体系、缺失值NaN/NA语义差异、PyArrow 与 object 双存储回退机制以及从objectdtype 迁移的兼容性要点。读完本文你将理解str、string、StringDtype(storage..., na_value...)之间的精确对应关系并掌握在当前仓库版本pandas 3.x中如何检查与配置这一行为。一、PDEP-14 要解决什么问题PDEP-14Proposal for pandas Enhancement是一份Accepted状态的设计文档创建于 2024 年 5 月 3 日作者 Joris Van den Bossche修订版本 1其核心提案可以概括为四点在 pandas 3.0 中默认启用一个名为str的专用字符串 dtype使其成为文本数据在构造、I/O 推断等场景下的默认类型取代objectdtype该默认字符串类型沿用与其他默认数据类型一致的缺失值语义即以NaN作为缺失值哨兵底层存储优先使用 PyArrow如果已安装否则回退到基于 numpy object-dtype 的内部等价实现更新安装指南明确鼓励用户安装 pyarrow 以获得默认的完整体验。为什么要做这个改变文档的 Background 部分指出pandas 长期以来默认把文本数据存放在objectdtype 的 NumPy 数组中存在两个主要缺陷语义不精确objectdtype 并非字符串专属任何 Python 对象都能放进去用户看到dtype: object无法判断列里到底是什么性能不佳Series 上的所有字符串方法最终都要逐个调用 Python 对象上的方法没有向量化的内核。解决第一个问题的专用扩展 dtype早在 pandas 1.0 就已引入即StringDtype但一直是 opt-in需要显式dtypestring。解决第二个问题的 PyArrow-backed 变体在 pandas 1.3 加入通过pd.StringDtype(storagepyarrow)指定。PDEP-10 曾提议让 pyarrow 成为硬依赖并在 3.0 默认启用 PyArrow 字符串类型但考虑到安装复杂度和包体积PDEP-14 将其软化为默认使用、但不强制依赖。同时NumPy 2.0 也开始提供原生变长字符串类型为未来提供了不依赖 Python 对象的另一条实现路径。二、源码视角StringDtype 的现状与实现在当前仓库中StringDtype定义于 pandas/core/arrays/string_.py 的StringDtype(StorageExtensionDtype)类约 L100-L405并通过register_extension_dtype注册为 pandas 的扩展 dtype。它的两个关键属性正是 PDEP-14 讨论的核心storagepythonobject-dtype 数组对应StringArray或pyarrow对应 Arrow 后端na_valuepd.NANA 语义或np.nanNaN 语义。从源码可以看到StringDtype.name根据缺失值语义动态返回property def name(self) - str: if self._na_value is libmissing.NA: return string else: return str即使用pd.NA的变体命名为string使用np.nan的新默认变体命名为str——与 PDEP-14 的命名提案完全一致。construct_from_string方法支持string、str仅当字符串 dtype 被启用时、string[python]、string[pyarrow]四种别名。在 pandas/core/config_init.py 中可以看到两个与该设计直接相关的配置项mode.string_storage合法值为[auto, python, pyarrow]默认auto。StringDtype.__init__在storage is None时读取该配置若为auto则按HAS_PYARROW决定回落到pyarrow还是python见 string_.pyfuture.infer_string其注册文档明确写道Whether to infer a sequence of str objects as str dtype rather than object dtype. This has been the default since pandas 3.0且该选项已标记为 deprecated、将在 pandas 4.0 移除见 config_init.py 与 L1045-L1053 的弃用通告——这正是 PDEP-14 Timeline 章节预期的落地结果3.0 中该 flag 默认开启。此外StringDtype.__init__对na_value做了严格校验只接受np.nan会被归一化为同一个np.nan实例便于is判断或pd.NA否则抛出ValueError当storagepyarrow但未安装 pyarrow 时抛出ImportError见 string_.py。三、缺失值语义NaN 与 NA 的区别这是 PDEP-14 最核心的技术决策。原始的StringDtypedtypestring或dtypepd.StringDtype()一直使用 pandas 1.0 引入的实验性哨兵pd.NA这带来两个后果字符串列遵循NA 语义NA在布尔运算如比较、谓词中传播NA a的结果是NA而非False对字符串列做数值或布尔结果的操作时返回可空类型例如ser.str.len()返回可空Int64pd.Int64Dtype()而非 numpyint64。但 pandas 其余所有默认数据类型至今仍使用 NaN 语义。若默认字符串类型用pd.NA用户在一次操作后就可能得到同一 DataFrame 里同时混有 NaN 语义列和 NA 语义列的混乱状态——例如同时出现两种int64、两种float64、两种bool。因此 PDEP-14 明确规定新的默认strdtype 使用NaN作为缺失值哨兵遵循 NaN 语义即布尔运算中NaN给出False不传播对字符串列操作产生数值/布尔结果时使用默认数据类型numpyint64/float64/bool。原文档还通过 pandas 2.2 的 opt-in 选项演示了预期行为 pd.options.future.infer_string True pd.Series([a, b, None]) 0 a 1 b 2 NaN dtype: string注意2.2 时期该选项只启用 PyArrow 后端且该变体的存储名曾叫pyarrow_numpyPDEP-14 提出后续 2.x 版本将扩展该选项使未安装 pyarrow 时也能启用 object-dtype 回退。源码层面NaN 语义的具体落实体现在BaseStringArray._str_map_nan_semantics见 string_.py当结果需要整数/布尔 dtype 时NaN会被映射为 0 或FalseNaN propagates as False且当掩码存在缺失且结果本应为整数时结果会被提升为float64——这与 numpy 默认整数列含缺失时提升为float64的行为一致正是返回默认数据类型的体现。相对地NA 语义走_str_map分支用IntegerArray/BooleanArray封装结果。测试文件 test_string.py 中也大量通过参数化(storage, na_value)组合pd.StringDtype(storagestorage, na_valuena_value)验证两种语义下的行为差异。四、存储后端PyArrow 与 object 回退为避免把 pyarrow 变成硬依赖PDEP-14 提出保留一个回退实现当 pyarrow 未安装时复用早已成熟的 numpy object-dtype 版本StringArray仅需为其增加一个新变体改动很小对应 GH-58451。在 3.0 中这是最现实的选择3.0 之后仍可继续探索基于 NumPy 2.0 字符串GH-58503或 nanoarrowGH-58552的实现但那只是实现细节对用户除性能外不应有直接影响。另一个重要决定即便是原有的pd.NA变体string其默认存储也改为与str相同的逻辑——优先pyarrow、否则回退python。这一逻辑在源码中由mode.string_storage的auto默认值统一实现见上文第二节。StringArray本身定义于 string_.py 附近继承BaseStringArray与NumpyExtensionArray其__init__期望一个元素为 Python 字符串或 nan-likeNone、np.nan、NA的 object-dtype 数组PyArrow 变体则位于 pandas/core/arrays/string_arrow.py。五、命名体系一张表说清所有别名PDEP-14 的 Naming 章节强调大多数用户不需要关心存储细节只需用通用别名str或string系统会根据 pyarrow 是否安装给出对应的默认存储。选择str而非string作为新默认 dtype 的别名既是为了保持dtypestring对既有pd.NA变体用户的向后兼容也因为在过去dtypestr/dtypestr已经能保证数据被转换为字符串只是结果为 object dtype。对于需要精确控制变体的高级用法StringDtype保留storage关键字并新增na_value关键字原pyarrow_numpy存储名因含义混乱将被弃用pandas 2.3 弃用、3.0 移除。文档给出的完整对照表如下用户写法具体得到的 dtype字符串别名备注未指定推断StringDtype(storagepyarrow\|python, na_valuenp.nan)str(1)str或StringDtype(na_valuenp.nan)StringDtype(storagepyarrow\|python, na_valuenp.nan)str(1)StringDtype(pyarrow, na_valuenp.nan)StringDtype(storagepyarrow, na_valuenp.nan)strStringDtype(python, na_valuenp.nan)StringDtype(storagepython, na_valuenp.nan)strStringDtype(pyarrow)StringDtype(storagepyarrow, na_valuepd.NA)string[pyarrow]StringDtype(python)StringDtype(storagepython, na_valuepd.NA)string[python]string或StringDtype()StringDtype(storagepyarrow\|python, na_valuepd.NA)string[pyarrow] 或 string[python](1)StringDtype(pyarrow_numpy)StringDtype(storagepyarrow, na_valuenp.nan)string[pyarrow_numpy](2)备注(1) 取 pyarrow 还是 python 取决于 pyarrow 是否安装(2) pyarrow_numpy 因已在已发布版本中出现而暂时保留2.x 弃用、3.0 移除。注意新默认strdtype 不允许通过字符串别名显式指定底层存储——字符串别名只是便利的快捷方式要做更细粒度的控制请使用显式的pd.StringDtype(storage..., na_valuenp.nan)。同理pd.NA变体通过字符串别名指定存储是否也要弃用被留作单独决策。值得强调的是在 pandas 3.x 当前仓库中使用类构造器获取默认 dtype 需要非默认参数pd.StringDtype(na_valuenp.nan)因此官方文档会引导用户使用dtypestr这种更简洁的写法。源码中StringDtype.__eq__与construct_from_string的实现string_.py保证str别名只有在字符串 dtype 处于启用状态时才可构造。六、备选方案讨论为什么不是别的做法PDEP-14 的 Alternatives 章节讨论了三个备选路径及其否决理由这有助于理解设计取舍为什么不推迟引入默认字符串 dtype推迟可以避开pyarrow 是否成为硬依赖pd.NA 是否成为默认哨兵NumPy 2.0 能力等仍在变动中的议题也能避免先切到 NaN、未来又切回 NA的反复。但推迟的代价同样明显一是进一步延后了专用字符串 dtype 在可用性与性能上的收益二是若 pandas 未来全面转向pd.NA届时需要迁移的是所有数据类型这不是字符串 dtype 独有的问题因此不构成推迟的理由。作者认为在 3.0 落地能让大多数用户受益值得承担又多一个 dtype 变体的复杂度。为什么不用现成的pd.NA版 StringDtype这个提案确实引入了更多变体表面看更乱但目的是让默认体验更统一如果新默认类型用pd.NA一次操作后用户就可能得到混合 NaN 语义与 NA 语义列的 DataFrame两种 int64、两种 float64、两种 bool 并存默认体验非常混乱。采用新变体后默认情况下用户只会看到一种整数 dtype、一种布尔 dtype只有显式 opt-in 才会获得pd.NA列。命名备选PDEP 初稿曾计划让string别名和默认pd.StringDtype()构造器指向新 dtype但围绕既有dtypepd.StringDtype()/dtypestring用户的向后兼容引发了大量讨论完整讨论见 GH-58613。最终方案是新别名用str但继续复用pd.StringDtype类保留storage关键字、新增na_value关键字把更大规模的 dtype 体系重构如新的构造器函数或命名空间留给未来。七、向后兼容性与迁移路径最可见的破坏性变更字符串列不再拥有objectdtype因此类似ser.dtype object的代码需要更新。该变更作为主版本3.0的硬性破坏引入——提前对推断变化发警告被认为过于嘈杂不值得。提前测试代码的方式是设置pd.options.future.infer_string True除了 dtype 本身字符串功能如.straccessor 方法总体上应保持原样。由于保留了 NaN 缺失值语义这一提案在缺失值维度也基本向后兼容一个细节差异是object dtype 下 pandas 允许用None表示缺失某些场景如shift甚至会自行引入None切换到新 dtype 后将统一使用NaN。对既有StringDtype用户已经显式使用pd.NA版StringDtype的代码应基本不受影响——最新版 PDEP 保留了dtypestring与dtypepd.StringDtype()指向pd.NA变体的语义。唯一建议的变更是将该变体的默认存储也改为pyarrow若可用但这对用户可见的影响很小。八、时间线从 2.1 的功能开关到 3.0 的默认行为PDEP-14 的 Timeline 章节记录了完整的演进路径pandas 2.1PyArrow-backed 未来字符串 dtype 已在功能开关后提供pd.options.future.infer_string Truepandas 2.2.xobject-dtype 变体被 backport便于更早测试pandas 2.3.0从 2.2.x 分支发布主分支已包含大量面向 3.0 的变更同时落地命名体系变更使所有未来字符串功能pyarrow 与 object-dtype 两种变体都可用pandas 3.0future.infer_string默认启用。对照当前仓库可确认这一时间线已兑现在 pandas/core/config_init.py 中future.infer_string的注册参数为legacyFalse, defaultTrue, upcomingTrue即默认开启其文档注明自 pandas 3.0 起这就是默认行为并已在 pandas 3.x 中发出Pandas4Warning弃用警告将于 pandas 4.0 彻底移除——届时字符串 dtype 的推断将不再可以被关闭。九、实践建议与检查清单结合 PDEP-14 的设计目标与当前仓库实现给读者的可操作建议如下查看当前生效的配置运行pd.options.mode.string_storage默认auto与pd.options.future.infer_string确认你的运行环境是否启用strdtype检查 pyarrow 是否安装若已安装默认存储为pyarrow性能更好未安装则自动回退python。可用pd.StringDtype()与pd.StringDtype(na_valuenp.nan)的 repr如StringDtype(na_valuenan)快速区分语义按缺失值语义选择写法默认场景统一用dtypestr或直接依赖推断需要pd.NA传播语义的老代码继续用dtypestring需要锁定后端/语义组合时用pd.StringDtype(storage..., na_value...)迁移存量代码搜索形如 object、astype(object)的字符串列判断逻辑并在 3.x 上以future.infer_string先行为准验证注意None与NaN在缺失值表示上的统一不要使用pyarrow_numpy它只是过渡期别名已在 2.x 弃用3.0 起请改用StringDtype(pyarrow, na_valuenp.nan)。这份 PDEP 的完整讨论、修订历史与设计权衡均记录在 web/pandas/pdeps/0014-string-dtype.md 中结合 pandas/core/arrays/string_.py、pandas/core/config_init.py 与 pandas/tests/arrays/string_/test_string.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),仅供参考
返回列表