小白python入门 - 63. 探索性分析与 seaborn

1. 本课定位:是什么、为何重要

matplotlib 精细但样板代码多;seaborn 面向统计探索:一条 API 画出「分布 / 关系 / 分类比较」,并更好处理 DataFrame 长表。

概念 一句话
EDA 探索性数据分析:在建模/下结论前,用图与摘要理解数据形态
seaborn 基于 matplotlib 的统计可视化库,数据集中式参数(data=, x=, y=, hue=
hue / col 用颜色或分面引入第三、第四变量

对比已学: 第 62 课「我指定几何(bar/plot/scatter)」;本课「我声明变量角色(x/y/hue),库选默认统计图」。


2. 先跑为敬:一秒出分布图

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
from pathlib import Path

plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei"]
plt.rcParams["axes.unicode_minus"] = False
Path("outputs").mkdir(exist_ok=True)

# 读取数据
clean = pd.read_csv("data/orders_clean.csv")
paid = clean.loc[clean["is_gmv"] == True]

# 一行代码:金额分布按渠道分色
sns.histplot(data=paid, x="amount", hue="channel", element="step", stat="density")
plt.title("各渠道金额分布")
plt.savefig("outputs/eda_hist.png", bbox_inches="tight")
plt.close()
print("saved")

3. 核心概念:宽表 vs 长表(tidy data)

seaborn 要求数据是长表(也叫 tidy data):一列一个变量,一行一个观测。

在这里插入图片描述

格式 特点 seaborn 能用?
宽表 渠道名成了列名(app/web 各一列) 不行,要先 melt
长表 渠道名成了值(一列 channel,一列 orders) 可以,直接用
import pandas as pd

# 宽表
wide = pd.DataFrame({"user": ["u1", "u2"], "app": [10, 5], "web": [3, 8]})

# 宽 → 长(seaborn 需要这种格式)
long = wide.melt(id_vars=["user"], var_name="channel", value_name="orders")
print(long)

记忆: seaborn 的 hue="channel" 需要有一列叫 channel。宽表里没有这列("app"和"web"是列名不是值),所以要先 melt。


4. 怎么读图:看到图要能说出一句话

出了图不是终点,能读懂才有价值。以下是每种图的"读法":

4.1 直方图 / KDE:分布长什么样?
看什么:数据集中在哪个区间?有没有拖尾?
说出的话:"金额主要集中在 20-80 元区间,少数订单超过 200 元(右偏/长尾)"

偏态怎么看? 直方图"尾巴"往右拖 = 右偏(大部分值小,少数特别大)。往左拖 = 左偏。对称 = 不偏。"右偏"在金额数据中非常常见——大部分订单金额不高,但偶尔有大单。

4.2 箱线图:分布 + 异常
看什么:箱体在哪?有没有超出须线的点?
说出的话:"app 渠道中位数 80 元,有 2 个超过 250 元的异常大单"

箱线图四分位:

  • 箱子下边 = 25 分位(Q1):25% 的数比它小
  • 箱子里面的线 = 中位数(Q2):50% 的数比它小
  • 箱子上边 = 75 分位(Q3):75% 的数比它小
  • 须线 = 1.5 倍箱体范围外的 = 可能的异常值(用点表示)
4.3 相关系数热力图:两个变量有没有关系
看什么:颜色深浅(接近 1 或 -1 = 强相关,接近 0 = 无关)
说出的话:"金额和订单数相关系数 0.85,说明大额订单往往来自高频用户"

相关系数直觉:

  • +1:完全正比——x 涨 y 一定涨(比如身高和鞋码)
  • 0:无关——x 涨跌和 y 没关系(比如身高和考试成绩)
  • -1:完全反比——x 涨 y 一定跌(比如温度和供暖费)

5. 内置能力:按 EDA 问题分组

5.1 分布
API 回答什么问题
直方图 sns.histplot 金额集中在哪个区间?
KDE 密度 sns.kdeplot 分布的平滑轮廓
箱线 sns.boxplot 中位数在哪?有没有异常值?
小提琴 sns.violinplot 箱线 + 密度的合体
5.2 关系
API 回答什么问题
散点 sns.scatterplot 两个数值变量是否同涨同跌?
带趋势线 sns.regplot 散点 + 线性趋势
相关热力 sns.heatmap(corr) 多个变量两两相关程度
5.3 分类比较
API 回答什么问题
条形聚合 sns.barplot 各类别的均值是多少?
计数 sns.countplot 各类别有多少个?

注意: sns.barplot 默认对 y 聚合(计算均值+置信区间),不是把每行当一根柱子。要画已聚合的 KPI 请用 matplotlib ax.bar


6. 实战:渠道金额分布对比(统一数据集)

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from pathlib import Path

plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei"]
plt.rcParams["axes.unicode_minus"] = False
Path("outputs").mkdir(exist_ok=True)

clean = pd.read_csv("data/orders_clean.csv")
paid = clean.loc[clean["is_gmv"] == True]

# 箱线图:各渠道金额分布
fig, ax = plt.subplots(figsize=(8, 5))
sns.boxplot(data=paid, x="channel", y="amount", ax=ax)
ax.set_title("各渠道金额分布(EDA)")
fig.savefig("outputs/eda_box.png", bbox_inches="tight")
plt.close(fig)
print("saved eda_box.png")

# 相关热力图
num_cols = paid[["amount"]].select_dtypes(include="number")
if len(num_cols.columns) >= 2:
    corr = num_cols.corr()
    sns.heatmap(corr, annot=True, cmap="RdBu")

业务解读: 若 app 箱体整体高于 web,回到第 60 课看 GMV 结构是否由客单驱动。


7. 安全规范写法

做法 原因
探索与终稿目录分开 outputs/eda/ vs outputs/report/
大数据 sample(n=5000) 再散点 性能与过度绘制
报告引用图注明样本与过滤 可审计
plt.close("all") 批量出图 防内存泄漏

8. 高阶技巧(点到)

技巧 说明
pairplot 多变量两两关系(列少时好用)
FacetGrid.map 自定义分面
调色板 sns.color_palette("Set2")
figure-level vs axes-level sns.relplot 自带分面;sns.scatterplot 塞进已有布局

9. 踩坑回顾

现象 正确做法
宽表直接 hue 画不出 melt 成长表
类别过多 hue 彩虹灾难 合并长尾或 TopN
把探索图直接贴进高管报告 信息噪声 探索用 seaborn,终稿用简化版
忽略 hue 样本不均 误判差异 同看样本量

10. 总结复盘

内容
学到什么 EDA 问题驱动选图、seaborn 变量角色、宽表长表、怎么读图
自学路线 探索图找线索 → 64 交互看板给业务点选 → 65 收敛成报告
思维拔高 先探索后结论;图用来证伪自己的假设,不是只用来美化
官方入口 seaborn tutorial

附录:统一数据集版

本课使用第 58 课清洗后的 data/orders_clean.csv

更多推荐