【问题标题】:Pandas ExtensionDtype / ExtensionArray custom format for to_csvPandas ExtensionDtype / ExtensionArray to_csv 的自定义格式
【发布时间】:2022-01-05 16:17:27
【问题描述】:

pandas extension interface (ExtensionDtype + ExtensionArray) 中,在Series 或包含此类列的DataFrame 上调用to_csv 函数时是否可以使用自定义格式?

似乎to_csv 函数会以某种方式调用底层标量类型对象的__str__ 函数。但是,我绝对希望在来自str() 和来自to_csv 的调用之间有不同的格式行为。

ExtensionArray documentation我们可以找到:

One can implement methods to handle parsing from strings that will be used in methods such as pandas.io.parsers.read_csv.

  - _from_sequence_of_strings

我对此非常满意,但这是为了读取字符串,而不是写入它。

【问题讨论】:

标签: python pandas csv


【解决方案1】:

我认为您只是想覆盖 _formatter 方法

https://github.com/pandas-dev/pandas/blob/5b2f4a531f38b8cc8a0b372aeae09c1d94fc99e8/pandas/core/arrays/base.py#L1248-L1274

默认情况下,它只在数组上调用str,但只要它返回一个将对象转换为字符串的可调用对象,您就可以将其覆盖为您想要的任何内容。

_formatter 在任何时候请求字符串表示时都在io.formats.format.format_array 中使用。

to_csv 使用ArrayManageriget_values 方法,我相信这是您必须编写的,但to_csv 也先将数组转换为本机类型,因此您可能只需要覆盖它也是。

将能够更详细地回答这个问题 - MRE 以及您调用 to_csv 的内容。

这里是_formatter,只是为了展示它是多么简单:

    def _formatter(self, boxed: bool = False) -> Callable[[Any], str | None]:
        """
        Formatting function for scalar values.
        This is used in the default '__repr__'. The returned formatting
        function receives instances of your scalar type.
        Parameters
        ----------
        boxed : bool, default False
            An indicated for whether or not your array is being printed
            within a Series, DataFrame, or Index (True), or just by
            itself (False). This may be useful if you want scalar values
            to appear differently within a Series versus on its own (e.g.
            quoted or not).
        Returns
        -------
        Callable[[Any], str]
            A callable that gets instances of the scalar type and
            returns a string. By default, :func:`repr` is used
            when ``boxed=False`` and :func:`str` is used when
            ``boxed=True``.
        """
        if boxed:
            return str
        return repr

【讨论】:

    【解决方案2】:

    不是一个确定的答案。

    更好地描述您想要实现的目标将有助于解决问题。 随时更新您的帖子以符合堆栈标准。

    出血边缘可能会破坏功能

    您引用的第一个通知对象是相当新的,可能会在您的流程中引入重大变化:

    pandas.api.extensions.ExtensionDtypepandas.api.extensions.ExtensionArray API 是新的实验性的。 它们可能会在版本之间更改而不会发出警告。

    跟上潮流总是好的。但也许您的主动方法要求比pandas 目前的要求更高。

    深入了解pandas 来源

    注意比pandas 严重依赖python对象模型和自省,它也执行了很多替换。

    import inspect
    import pandas as pd
    pd.__version__  # 1.3.5
    

    例如,找到read_csv 的来源并不简单:

    inspect.getsourcefile(pd.read_csv)
    # ./pandas/util/_decorators.py
    

    这很不走运,但仍然可以找到来源:

    inspect.getsource(pd.read_csv)
    

    这就解释了为什么我们被路由到_decorator.py

    @deprecate_nonkeyword_arguments(
        version=None, allowed_args=["filepath_or_buffer"], stacklevel=3
    )
    # ...
    def read_csv(
        filepath_or_buffer: FilePathOrBuffer,
    # ...
        return _read(filepath_or_buffer, kwds)
    

    稍作搜索,您可能会在GitHub 上找到该文件。

    检查未来的Extension 对象

    阅读ExtensionDtypeExtensionArray的源码,暴露了具体的转换方法。

    正如@sneakers-the-rat 所发现的,ExtensionArray 中有一个 _formatter 方法,一旦我们知道您的目标是什么,这可能是一个很好的尝试。

    探索to_csv 堆栈

    这种方法更容易找到,但它有很多间接级别。您可以探索它here。关键是它返回一个DataFrameRenderer 对象:

    @final
    @doc(storage_options=_shared_docs["storage_options"])
    def to_csv(
        self,
        path_or_buf: FilePathOrBuffer[AnyStr] | None = None,
        # ...
    ):
        # ...
        return DataFrameRenderer(formatter).to_csv(
            # ...
        )
    

    它被定义为here,并且还使用了CSVFormatter 定义的here 对象。

    这个最终对象包含将DataFrame 转换为 CSV 文件的整个逻辑。但它没有明确使用

    • ExtensionDtypeExtensionArray 对象或对象方法;
    • 字符串转换使用strrepr或相关魔术方法__str____repr__方法。

    中间结论

    这不是详尽的搜索,也不是证明它不可行的证据,但这在很大程度上取决于您想要实现的目标。更精确的定义将有助于找到解决方案。

    此答案基于撰写本文时的最新版本 (1.3.5)。 Pandas 框架发展迅速。

    使用自己的框架扩展 pandas 无疑是个好主意。无论如何,目前看来您将不得不等待:

    • 扩展对象以公开导出功能以及导入;
    • 要在导出流程中映射的转换功能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-05
      • 2020-09-20
      • 2017-08-01
      • 2014-11-29
      • 1970-01-01
      • 1970-01-01
      • 2016-06-12
      相关资源
      最近更新 更多