| name | stat-viz |
| description | 创建高质量统计图表的指南。包含图表类型选择、常见错误避免、中文字体配置、代码模板。 |
| argument-hint | <week_id> [chart_type] |
| allowed-tools | Read, Write, Edit, Grep, Glob, Bash, WebSearch |
| disable-model-invocation | true |
/stat-viz
用法
/stat-viz week_XX # 显示本周应该生成的图表类型
/stat-viz week_XX histogram # 生成特定类型的图表
目标
为 chapters/week_XX/ 创建高质量的统计图表:
- 图表代码保存在
examples/NN_chart_xxx.py(可复现)
- 图片输出到
images/xxx.png(嵌入正文)
- 确保中文字体正确显示
- 避免常见的可视化错误
第一部分:图表类型选择指南
什么时候用什么图
| 你想展示什么 | 推荐图表 | Seaborn 函数 |
|---|
| 单变量分布 | 直方图 + KDE | sns.histplot(data, kde=True) |
| 分布形状 + 离群点 | 箱线图 | sns.boxplot(x=data) |
| 多组分布对比 | 小提琴图 | sns.violinplot(x=group, y=value) |
| 两组变量关系 | 散点图 | sns.scatterplot(x=x, y=y) |
| 关系 + 趋势线 | 散点图 + 回归 | sns.regplot(x=x, y=y) |
| 多变量关系 | 相关矩阵热图 | sns.heatmap(corr, annot=True) |
| 分类变量分布 | 计数图 | sns.countplot(x=cat) |
| 时间序列趋势 | 折线图 | sns.lineplot(x=time, y=value) |
不推荐的图表类型
| 避免 | 原因 | 替代方案 |
|---|
| 3D 图表 | 透视 distort 数值感知 | 2D 图表 + 分面 |
| 饼图(>5类) | 人眼难以比较角度 | 条形图 |
| 双 Y 轴 | 制造假相关 | 分开两个图 |
| 过多颜色 | 认知过载 | 使用色调渐变或分组 |
第二部分:常见错误与修复
参考来源:
错误 1:截断 Y 轴
plt.ylim(95, 100)
plt.ylim(0, None)
例外:折线图可以不从 0 开始,但要在图注中说明。
错误 2:樱桃采摘(Cherry-picking)
df[df['metric'] > threshold]
plt.axvspan(xmin, xmax, alpha=0.2, color='yellow', label='关注区域')
错误 3:3D 效果
g = sns.FacetGrid(df, col='category')
g.map(sns.histplot, 'value')
错误 4:不当缩放(气泡图/面积图)
plt.scatter(x, y, s=size)
plt.scatter(x, y, s=size**2)
错误 5:信息过载
sns.scatterplot(data=df, x='a', y='b', hue='c', size='d', style='e')
g = sns.relplot(data=df, x='a', y='b', hue='c', col='e')
第三部分:中文字体配置
检测可用中文字体
import matplotlib.font_manager as fm
fonts = [f.name for f in fm.fontManager.ttflist
if 'Hei' in f.name or 'CJK' in f.name or 'Song' in f.name]
print(sorted(set(fonts)))
推荐配置(按优先级)
import matplotlib.pyplot as plt
import matplotlib as mpl
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC', 'Noto Sans CJK JP']
plt.rcParams['axes.unicode_minus'] = False
def get_chinese_font():
"""自动检测可用的中文字体"""
chinese_fonts = ['SimHei', 'Noto Sans CJK SC', 'Arial Unicode MS',
'PingFang SC', 'Microsoft YaHei', 'WenQuanYi Micro Hei']
available = [f.name for f in fm.fontManager.ttflist]
for font in chinese_fonts:
if font in available:
return font
return 'DejaVu Sans'
plt.rcParams['font.sans-serif'] = [get_chinese_font()]
plt.rcParams['axes.unicode_minus'] = False
验证字体配置
fig, ax = plt.subplots(figsize=(6, 4))
ax.text(0.5, 0.5, '中文测试:均值、标准差、箱线图',
fontsize=20, ha='center', va='center')
ax.set_title('中文字体验证')
plt.savefig('test_chinese.png')
plt.close()
第四部分:代码模板(必须保存到 examples/)
模板:生成图片并保存代码
"""
示例:生成月薪分布直方图(展示右偏分布)。
运行方式:python3 chapters/week_XX/examples/03_salary_histogram.py
预期输出:生成 images/salary_distribution.png
本代码演示:
1. 中文字体配置
2. 直方图 + KDE
3. 均值/中位数标注
4. 高质量导出设置
"""
from __future__ import annotations
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import numpy as np
import pandas as pd
from pathlib import Path
def setup_chinese_font() -> str:
"""配置中文字体,返回使用的字体名称"""
chinese_fonts = ['SimHei', 'Noto Sans CJK SC', 'Arial Unicode MS',
'PingFang SC', 'Microsoft YaHei']
available = [f.name for f in fm.fontManager.ttflist]
for font in chinese_fonts:
if font in available:
plt.rcParams['font.sans-serif'] = [font]
plt.rcParams['axes.unicode_minus'] = False
return font
plt.rcParams['font.sans-serif'] = ['DejaVu Sans']
return 'DejaVu Sans'
def generate_sample_data() -> pd.DataFrame:
"""生成示例数据(右偏的月薪分布)"""
np.random.seed(42)
base = np.random.lognormal(mean=10.5, sigma=0.3, size=500)
high_earners = np.random.uniform(50000, 100000, size=20)
salaries = np.concatenate([base, high_earners])
return pd.DataFrame({'月薪': salaries})
def main() -> None:
font = setup_chinese_font()
print(f"使用字体: {font}")
df = generate_sample_data()
mean_salary = df['月薪'].mean()
median_salary = df['月薪'].median()
fig, ax = plt.subplots(figsize=(10, 6))
ax.hist(df['月薪'], bins=50, density=True, alpha=0.7,
color='steelblue', edgecolor='white', label='分布')
from scipy import stats
kde = stats.gaussian_kde(df['月薪'])
x_range = np.linspace(df['月薪'].min(), df['月薪'].max(), 200)
ax.plot(x_range, kde(x_range), 'r-', linewidth=2, label='KDE')
ax.axvline(mean_salary, color='red', linestyle='--', linewidth=2,
label=f'均值: {mean_salary:,.0f}')
ax.axvline(median_salary, color='green', linestyle='-', linewidth=2,
label=f'中位数: {median_salary:,.0f}')
ax.set_xlabel('月薪(元)', fontsize=12)
ax.set_ylabel('密度', fontsize=12)
ax.set_title('月薪分布:右偏,均值被高薪极值拉高', fontsize=14)
ax.legend(loc='upper right', fontsize=10)
output_dir = Path(__file__).parent.parent / 'images'
output_dir.mkdir(exist_ok=True)
output_path = output_dir / 'salary_distribution.png'
plt.savefig(output_path, dpi=150, bbox_inches='tight',
facecolor='white', edgecolor='none')
plt.close()
print(f"图片已保存: {output_path}")
print(f"均值: {mean_salary:,.0f}, 中位数: {median_salary:,.0f}")
print(f"均值 > 中位数,说明分布右偏")
if __name__ == '__main__':
main()
第五部分:Week 各阶段推荐图表
| 阶段 | 周次 | 推荐图表 |
|---|
| 数据探索 | 01-04 | 直方图、箱线图、散点图、相关矩阵 |
| 统计推断 | 05-08 | Q-Q图、置信区间图、效应量森林图 |
| 预测建模 | 09-12 | 残差图、ROC曲线、学习曲线、特征重要性 |
| 高级专题 | 13-15 | DAG因果图、后验分布、SHAP图 |
执行流程
当调用此 skill 时:
- 读取本周主题:从
chapters/week_XX/CHAPTER.md 确定需要什么图表
- 检查现有图片:查看
images/ 目录
- 生成缺失的图表:
- 代码保存到
examples/NN_chart_xxx.py
- 图片保存到
images/xxx.png
- 在 CHAPTER.md 中插入引用
- 验证:运行代码确认图片正确生成
- 更新验证:确保
validate_week.py 仍然通过