Pandas: 风格化输出

最后更新:2026-08-26

数据分析的最后一步是"呈现"——让数字自己说话。Pandas Styler 让 DataFrame 变成彩色报告:销售额高的绿色、低的红色、进度条内嵌、最大值高亮。不用 Excel 手动调色,Pandas 自己就能做。

⚠️ 注意: 以下代码需在本地 Python 环境中运行。

1. 你将学到


2. Carol 的销售报表美化

(1) 痛点:纯数字报表不够直观

Carol 的月度销售报表全是数字,老板看不出高低:

PYTHON
import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'region': ['North', 'South', 'East', 'West'],
    'sales': [5200, 3100, 4800, 2900],
    'profit': [1560, 620, 1440, 435],
    'margin': [0.30, 0.20, 0.30, 0.15]
})
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

(2) 解法:Styler 一行美化

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:Styler 基础(难度⭐)

PYTHON
import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'region': ['North', 'South', 'East', 'West'],
    'sales': [5200, 3100, 4800, 2900],
    'profit': [1560, 620, 1440, 435],
    'margin': [0.30, 0.20, 0.30, 0.15]
})

# Chain styling methods
styled = (df.style
    .format({'sales': '${:,.0f}', 'profit': '${:,.0f}', 'margin': '{:.1%}'})
    .background_gradient(subset=['sales'], cmap='RdYlGn')
    .highlight_max(subset=['profit'], color='lightgreen')
)
# styled in Jupyter shows the styled table
# styled.to_html('report.html') for export
print("Styled table created!")
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

3. Styler 对象

(1) df.style 返回 Styler

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:Styler 基础操作(难度⭐)

PYTHON
import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'product': ['A', 'B', 'C', 'D', 'E'],
    'price': [29.99, 99.99, 149.99, 499.99, 9.99],
    'stock': [50, 120, 80, 35, 200],
    'rating': [4.5, 4.2, 3.8, 4.8, 4.0]
})

# df.style returns Styler (not DataFrame!)
styler = df.style
print(type(styler))  # pandas.io.formats.style.Styler

# Chain multiple styles
result = (df.style
    .format({'price': '${:.2f}', 'rating': '{:.1f}/5.0'})
    .set_caption('Product Catalog')
    .set_properties(**{'text-align': 'center'}, subset=['price', 'rating'])
)
# result renders in Jupyter

# Styler does NOT modify original DataFrame
print(df['price'].dtype)  # still float64, unchanged
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

4. format 格式化

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:format 数值格式化(难度⭐)

PYTHON
import pandas as pd
import numpy as np

df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'salary': [75000.50, 92000.75, 68000.25],
    'bonus': [0.15, 0.20, 0.10],
    'performance': [4.567, 3.891, 4.123]
})

styled = df.style.format({
    'salary': '${:,.2f}',         # $75,000.50
    'bonus': '{:.0%}',             # 15%
    'performance': '{:.1f}/5.0'    # 4.6/5.0
})

# Format all numeric columns
styled2 = df.style.format(precision=2)  # 2 decimal places for all

# Thousands separator
styled3 = df.style.format({'salary': '{:,.0f}'})  # 75,001

# Custom formatter function
styled4 = df.style.format({
    'salary': lambda x: f'${x:,.0f}'
})
print("Formatted tables created!")
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

5. background_gradient 热力高亮

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:background_gradient 热力图(难度⭐⭐)

PYTHON
import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'region': ['North', 'South', 'East', 'West'],
    'Q1': [5200, 3100, 4800, 2900],
    'Q2': [5800, 3400, 5100, 3100],
    'Q3': [6100, 3800, 5600, 3500],
    'Q4': [6500, 4100, 5900, 3800]
}).set_index('region')

# Heatmap: RdYlGn (red-yellow-green)
styled = df.style.background_gradient(cmap='RdYlGn')

# Subset: only specific columns
styled2 = df.style.background_gradient(
    subset=['Q1', 'Q4'],
    cmap='Blues',
    vmin=2000, vmax=7000
)

# Per-column gradient (each column scaled independently)
styled3 = df.style.background_gradient(cmap='YlOrRd', axis=0)

# Per-row gradient (each row scaled independently)
styled4 = df.style.background_gradient(cmap='YlOrRd', axis=1)
print("Heatmap styles created!")
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

(1) 常用 cmap

cmap 效果 适用
RdYlGn 红→黄→绿 越高越好
RdYlBu 红→黄→蓝 双向
Blues 浅→深蓝 单向增强
YlOrRd 黄→橙→红 越高越严重
coolwarm 蓝→红 偏差

6. bar 条形图内嵌

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:bar 内嵌条形(难度⭐⭐)

PYTHON
import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'product': ['A', 'B', 'C', 'D', 'E'],
    'sales': [5200, 3100, 4800, 2900, 6500],
    'target': [5000, 4000, 5000, 3000, 6000]
})

# Bar inside cells
styled = df.style.bar(
    subset=['sales'],
    color='lightblue',
    vmin=0, vmax=7000
)

# Achievement: bar shows % of target
df['achievement'] = (df['sales'] / df['target'] * 100).round(1)
styled2 = df.style.bar(
    subset=['achievement'],
    color=['#ff6b6b', '#51cf66'],  # red < 100%, green >= 100%
    vmin=0, vmax=150
)
print("Bar chart styles created!")
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

7. highlight 条件标记

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:highlight_max/min/null(难度⭐⭐)

PYTHON
import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'product': ['A', 'B', 'C', 'D', 'E'],
    'price': [29.99, 99.99, 149.99, 499.99, 9.99],
    'stock': [50, 120, 80, 35, np.nan],
    'rating': [4.5, 4.2, 3.8, 4.8, 4.0]
})

# Highlight max value per column
styled = df.style.highlight_max(
    subset=['price', 'stock', 'rating'],
    color='lightgreen'
)

# Highlight min value
styled2 = df.style.highlight_min(
    subset=['price', 'rating'],
    color='lightcoral'
)

# Highlight NaN values
styled3 = df.style.highlight_null(color='yellow')

# Custom: highlight low stock (< 40)
def highlight_low_stock(val):
    color = 'red' if val < 40 else ''
    return f'background-color: {color}'

styled4 = df.style.applymap(highlight_low_stock, subset=['stock'])
# Note: applymap renamed to map in Pandas 2.x
# styled4 = df.style.map(highlight_low_stock, subset=['stock'])
print("Highlight styles created!")
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

8. 完整示例:销售报表风格化

(5) ▶ 风格化链式流程

100%
graph LR
    A[df.style] --> B[format 格式化]
    B --> C[background_gradient 热力图]
    C --> D[bar 内嵌条形图]
    D --> E[highlight 条件标记]
    E --> F[set_caption 标题]
    F --> G[to_html / to_excel 导出]
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:综合报表风格化(难度⭐⭐⭐)

PYTHON
import pandas as pd
import numpy as np

# ============================================
# Comprehensive example: Sales report styling
# format → gradient → bar → highlight → export
# ============================================

np.random.seed(42)
df = pd.DataFrame({
    'region': ['North', 'South', 'East', 'West', 'Central'],
    'revenue': [520000, 310000, 480000, 290000, 410000],
    'cost': [364000, 248000, 336000, 246500, 307500],
    'profit': [156000, 62000, 144000, 43500, 102500],
    'margin': [0.30, 0.20, 0.30, 0.15, 0.25],
    'growth': [0.12, -0.05, 0.08, -0.10, 0.15],
    'customers': [1200, 850, 1100, 680, 950]
}).set_index('region')

# Multi-style chain
styled = (df.style
    .format({
        'revenue': '${:,.0f}',
        'cost': '${:,.0f}',
        'profit': '${:,.0f}',
        'margin': '{:.1%}',
        'growth': '{:+.1%}',
        'customers': '{:,}'
    })
    .background_gradient(subset=['margin'], cmap='RdYlGn', vmin=0, vmax=0.4)
    .bar(subset=['customers'], color='lightblue', vmin=0)
    .highlight_max(subset=['profit'], color='lightgreen')
    .highlight_min(subset=['profit'], color='lightcoral')
    .set_caption('2024 Regional Sales Report')
    .set_properties(**{'text-align': 'right'}, subset=['revenue', 'cost', 'profit'])
)

# Export
# styled.to_html('report.html')
# styled.to_excel('report.xlsx', engine='openpyxl')
print("Full styled report created!")
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

❓ 常见问题

Q Styler 修改数据吗?
A 不会——Styler 只影响显示,原 DataFrame 数据不变。df.style 是"视图层"修饰,不触及"数据层"。格式化后 df['salary'] 仍然是 float64,不是字符串。可以安全地对同一 DataFrame 创建多个不同风格的 Styler。
Q background_gradient 的 cmap 怎么选?
A 越高越好看用 RdYlGn(红→绿),越高越差用 YlOrRd(黄→红),双向偏差用 coolwarm(蓝→红),单向增强用 Blues。选 cmap 的原则:颜色直觉匹配业务含义。在 Jupyter 中试试效果再定。
Q subset 怎么指定范围?
A 三种方式:① 列名列表 subset=['sales', 'profit'];② 切片 subset=pd.IndexSlice[:, 'Q1':'Q4'];③ 条件筛选 subset=pd.IndexSlice[df['sales'] > 3000, :]。最常用列名列表。
Q to_html 中文乱码?
A 指定 encoding:styled.to_html(encoding='utf-8')。如果用文件写入,用 with open('report.html', 'w', encoding='utf-8') as f: f.write(styled.to_html())。确保 HTML 文件声明 <meta charset="utf-8">
Q 样式能导出 Excel 吗?
A 能——styled.to_excel('report.xlsx', engine='openpyxl')。颜色和格式会保留到 Excel 中。但部分样式可能不完全一致(如 bar 内嵌图在 Excel 中是条件格式)。需要 pip install openpyxl
Q applymap 和 map 区别?
A Pandas 2.x 中 Styler.applymap 重命名为 Styler.map。功能相同——对每个单元格应用样式函数。apply 按行/列应用(axis 参数),map 按单元格应用。新版用 map 即可。
Q 如何链式组合多个样式?
A Styler 方法返回 Styler 对象,天然支持链式:df.style.format({...}).background_gradient(...).bar(...).highlight_max(...)。从上到下依次应用,后应用的会覆盖前面的冲突样式。建议顺序:format → gradient → bar → highlight → set_caption。

📖 小节


📝 作业

  1. 基础题(难度⭐):创建含 salary/bonus 列的 DataFrame,用 format 格式化为货币和百分比,用 highlight_max 标记最高薪资。
  2. 进阶题(难度⭐⭐):创建季度销售 DataFrame(行=地区,列=Q1-Q4),用 background_gradient(cmap='RdYlGn') 热力图 + bar 内嵌条形 + format 千分位格式化。
  3. 挑战题(难度⭐⭐⭐):模拟 5 地区销售报表(revenue/cost/profit/margin/growth),完成 5 步链式风格化:format 多格式 → gradient(margin) → bar(customers) → highlight_max(profit) → to_html 导出。

← 上一课:性能优化 · 下一课:项目-数据分析 →

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏