Pandas: 风格化输出
最后更新:2026-08-26
数据分析的最后一步是"呈现"——让数字自己说话。Pandas Styler 让 DataFrame 变成彩色报告:销售额高的绿色、低的红色、进度条内嵌、最大值高亮。不用 Excel 手动调色,Pandas 自己就能做。
⚠️ 注意: 以下代码需在本地 Python 环境中运行。
1. 你将学到
- ❶ Styler 对象
- ❷ format 格式化
- ❸ background_gradient 热力高亮
- ❹ bar 条形图内嵌
- ❺ highlight 条件标记
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) ▶ 风格化链式流程
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。📖 小节
- df.style 返回 Styler 对象,只影响显示不修改数据
- format 格式化数值:货币(${:,.0f})/百分比({:.0%})/精度(precision)
- background_gradient 热力图高亮,cmap 选色,subset 选范围,axis 控制方向
- bar 内嵌条形图,color 单色或双颜色,vmin/vmax 控制范围
- highlight_max/min/null 条件高亮,map/apply 自定义条件
- 链式组合:format → gradient → bar → highlight → caption
- to_html/to_excel 导出带样式的报告
📝 作业
- 基础题(难度⭐):创建含 salary/bonus 列的 DataFrame,用 format 格式化为货币和百分比,用 highlight_max 标记最高薪资。
- 进阶题(难度⭐⭐):创建季度销售 DataFrame(行=地区,列=Q1-Q4),用 background_gradient(cmap='RdYlGn') 热力图 + bar 内嵌条形 + format 千分位格式化。
- 挑战题(难度⭐⭐⭐):模拟 5 地区销售报表(revenue/cost/profit/margin/growth),完成 5 步链式风格化:format 多格式 → gradient(margin) → bar(customers) → highlight_max(profit) → to_html 导出。