小白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-levelsns.relplot 自带分面;sns.scatterplot 塞进已有布局

9. 踩坑回顾

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

10. 总结复盘

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

附录:统一数据集版

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

更多推荐