簡體   English   中英

帶有條件規則的 Pandas 樣式

[英]Pandas Styling with Conditional Rules

我試圖使用 2 個不同的列來設置 Pandas Dataframe 的樣式。 只要條件與列本身有關,我就成功了,但是當它依賴於另一個時,我無法獲得所需的結果。

如果“Date I”是過去的,我想為“Date II”中的單元格着色。

def date_pii(row):
        ret = ["" for _ in row.index]
        print(row['Date PI'])
        if row['Date PI'] < datetime.now():
            ret[row.index.get_loc("Date PII")] = "background-color: red"
            return ret

styler = df3.style \
        .applymap(lambda x: 'background-color: %s' % 'red' if x <= datetime.now() else '', subset=['Date PI']) \
        .applymap(lambda x: 'background-color: %s' % 'yellow' if x < datetime.now() + timedelta(days=30) else '',
                  subset=['Date PII']) \
        .applymap(lambda x: 'background-color: %s' % 'orange' if x <= datetime.now() else '', subset=['Date PII']) \
        .applymap(lambda x: 'background-color: %s' % 'grey' if pd.isnull(x) else '', subset=['Date PI'])\
        .applymap(lambda x: 'background-color: %s' % 'grey' if pd.isnull(x) else '', subset=['Date PII'])\
        .apply(date_pii, axis=1) ----> THIS IS THE ISSUE

styler.to_excel(writer, sheet_name='Report Paris', index=False)

在運行時,我收到以下錯誤:

ValueError: Function <function generate_report_all.<locals>.date_pii at 0x7fd3964d9160> returned the wrong shape.
Result has shape: (532,)
Expected shape:   (532, 10)

數據框如下所示: df3

“Date PII”中的第一個橙色單元格是正確的,但是,其余的(PI 為紅色)我希望它們也變成紅色。

謝謝您的幫助!

解決此類問題的一般方法是將指定的列作為subset傳遞給Styler.apply 這允許我們在 DataFrame 級別創建樣式並使用loc索引根據條件構建樣式。 另一個主要好處是,我們可以使用額外的空間來提供文檔,而不是鏈接,還可以減少所有這些 lambda 的開銷:

def style_dates(subset_df):
    # Empty Styles
    style_df = pd.DataFrame(
        '', index=subset_df.index, columns=subset_df.columns
    )
    # Today's Date
    today = pd.Timestamp.now().normalize()
    # Date PII is within 30 days from today
    style_df.loc[
        subset_df['Date PII'].le(today + pd.Timedelta(days=30)),
        'Date PII'
    ] = 'background-color: yellow'

    # Date PI is before today
    style_df.loc[
        subset_df['Date PI'].lt(today),
        ['Date PI', 'Date PII']
    ] = 'background-color: red'

    # Date PII is before today and Date PI is after Today
    style_df.loc[
        subset_df['Date PII'].lt(today) & subset_df['Date PI'].gt(today),
        'Date PII'
    ] = 'background-color: orange'

    # Either is NaN
    style_df[subset_df.isna()] = 'background-color: gray'
    return style_df


styler = df3.style.apply(
    style_dates, axis=None, subset=['Date PII', 'Date PI']
).format(
    # Optional Explicit Date Format
    formatter='{:%Y-%m-%d}', na_rep='NaT', subset=['Date PII', 'Date PI']
)

樣式化數據框


設置 DataFrame 總是相對於當前日期隨機生成(樣式將保持一致,而日期則不會):

import numpy as np
import pandas as pd
from numpy.random import Generator, MT19937

norm_today = pd.Timestamp.now().normalize()
rng = Generator(MT19937(1023))


def md(lower_bound, upper_bound, rng_=rng):
    return pd.Timedelta(days=rng_.integers(lower_bound, upper_bound))


df3 = pd.DataFrame({
    'Desc': [
        'PII within 30 days',  # PII yellow
        'PII in past and PI in future',  # PII orange
        'PI past',  # Both red
        'PI empty',  # grey
        'PII empty',  # grey
        'PII in future but not within 30 days'  # No Styles
    ],
    'Date PII': [norm_today + md(1, 10), norm_today - md(1, 10),
                 norm_today, norm_today, np.nan,
                 norm_today + md(40, 50)],
    'Date PI': [norm_today, norm_today + md(1, 10),
                norm_today - md(1, 10), np.nan, norm_today,
                norm_today]
})
描述 日期 PII 日期 PI
30 天內的 PII 2021-11-06 00:00:00 2021-11-03 00:00:00
過去的 PII 和未來的 PI 2021-10-31 00:00:00 2021-11-11 00:00:00
PI過去 2021-11-03 00:00:00 2021-11-01 00:00:00
PI 空 2021-11-03 00:00:00 鈉鹽
PII 空 鈉鹽 2021-11-03 00:00:00
PII 在未來但不是在 30 天內 2021-12-19 00:00:00 2021-11-03 00:00:00

雖然@HenryEcker 解決方案適用於 DataFrame 級別(注意他使用了axis=None關鍵字參數),但有時可能需要更簡單的方法。

由於您的條件完全取決於行,因此您可以將 apply 與axis=1並附加一個基於每行中的列值進行計算的函數。

例如:

df = DataFrame([[1,2,3],[3,2,1]], index=["i", "j"], columns=["A", "B", "C"])

   A   B   C
i  1   2   3
j  3   2   1

假設我們要突出顯示C列,如果它小於A列:

def highlight(s):
    if s["C"] < s["A"]
        return ["", "color: red;"]
    return ["", ""]

df.style.apply(highlight, subset=["A", "C"], axis=1)

在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM