繁体   English   中英

更改 pandas.DataFrame 的样式:永久?

[英]Changing style of pandas.DataFrame: Permanently?

当我更改pandas.DataFrame的样式时,例如像这样

        # color these columns
        color_columns = ['roi', 'percent_of_ath']
        (portfolio_df
            .style
            # color negative numbers red
            .apply(lambda v: 'color: red' if v < 0 else 'color: black',
                   subset=color_columns)
            # color selected cols light blue
            .apply(lambda s: 'background-color: lightblue',
                    subset=color_columns))

应用于 dataframe 的 styles 不是永久性的。

为了让它们坚持下去,我可以将(portfolio_df...部分的 output 分配给相同的 dataframe,如下所示:

portfolio_df = (portfolio_df ...

在 Jupyter Notebook 中显示这个覆盖的portfolio_df ,我可以看到样式精美的 DataFrame。但是尝试从从模块导入的 function 中更改样式,我失败了。 我在 function 中构建 DataFrame,更改样式,从 function 返回(现在)样式化的 DataFrame,在 Jupyter Notebook 中显示它,我看到一个非样式化的 DataFrame。

编辑

检查样式操作返回值的类型

s = (portfolio_df.style.apply(...

我看到这个:

>>> type(s)
pandas.io.formats.style.Styler

所以操作返回的不是DataFrame,而是...Styler object。我错误地认为我可以将这个返回值重新分配给我原来的DataFrame,从而覆盖它并使样式更改永久。

问题

对DataFrame应用样式的操作是破坏性操作还是非破坏性操作? 答案似乎是样式不会永久更改。 现在,我怎样才能让它永久改变呢?

编辑 2

查看Pandas的源代码,我查看了class Styler的文档字符串(参见 [1]):

    If using in the Jupyter notebook, Styler has defined a ``_repr_html_``
    to automatically render itself. Otherwise call Styler.render to get
    the generated HTML.

因此,在 Jupyter notebook 中,Styler 有一种方法可以根据应用的样式自动呈现 dataframe。

否则(在 iPython 中)它创建 HTML。

将应用样式的返回值分配给变量

s = (portfolio_df.style.apply(...

我可以在 Jupyter notebook 中使用它来呈现新样式。

我的理解是:我不能将 output 我的 dataframe 放入 Jupyter 笔记本并期望它呈现新样式。 但我可以 output s来展示新风格。


[1] class Styler

pandas/pandas/io/formats/style.py

文档字符串,第 39 行。

我可以给你两个建议:

1. 写一个简单的 function 来显示你的数据帧

这是迄今为止最简单、最简单的解决方案。 你可以写:

def my_style(df:pd.DataFrame, color_columns:list[str]=['roi', 'percent_of_ath']):
    return (df
            .style
            .applymap(lambda v: 'color: red' if v < 0 
                                 else None, subset=color_columns)
           )    

这使您可以编写如下代码:

df.pipe(my_style) # This will output a formatted dataframe

或者

from IPython.display import display 

# This will print a nicely formatted dataframe
def my_display(df:pd.DataFrame, style=my_style):
    display(df.pipe(style))

2.覆盖Pandas_repr_html_方法

我不建议这样做,但这是您所要求的;)

from pandas._config import get_option
from pandas.io.formats import format as fmt

def _my_repr_html_(self) -> str | None:
        """
        Return a html representation for a particular DataFrame.

        Mainly for IPython notebook.
        """
        if self._info_repr():
            buf = StringIO()
            self.info(buf=buf)
            # need to escape the <class>, should be the first line.
            val = buf.getvalue().replace("<", r"&lt;", 1)
            val = val.replace(">", r"&gt;", 1)
            return "<pre>" + val + "</pre>"

        if get_option("display.notebook_repr_html"):
            max_rows = get_option("display.max_rows")
            min_rows = get_option("display.min_rows")
            max_cols = get_option("display.max_columns")
            show_dimensions = get_option("display.show_dimensions")

            formatter = fmt.DataFrameFormatter(
                self,
                columns=None,
                col_space=None,
                na_rep="NaN",
                formatters=None,
                float_format=None,
                sparsify=None,
                justify=None,
                index_names=True,
                header=True,
                index=True,
                bold_rows=True,
                escape=True,
                max_rows=max_rows,
                min_rows=min_rows,
                max_cols=max_cols,
                show_dimensions=show_dimensions,
                decimal=".",
            )
            # return fmt.DataFrameRenderer(formatter).to_html(notebook=True)
            return self.pipe(my_style).to_html(notebook=True) # <<<< !!! HERE !!! 
        else:
            return None
        
df.pipe(_my_repr_html_)

pd.DataFrame._repr_html_ = _my_repr_html_

当心。 此示例代码不处理很长或很宽的数据帧。

编辑:

上面用于覆盖repr_html的代码对 pandas 代码进行了最少的编辑。 这是一个最小的工作示例:

def my_style(df:pd.DataFrame, color_columns:list[str]=['roi', 'percent_of_ath']):
    return (df.style.applymap(
            lambda v: 'color: red' if v < 0 else None, subset=color_columns)
           ) 

def _my_repr_html_(self) -> str | None:
    return self.pipe(my_style)._repr_html_() # <<<< !!! HERE !!! 
        
pd.DataFrame._repr_html_ = _my_repr_html_

尝试使用此功能

df.style.applymap()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM