数据收集与探索:先把手弄脏

做接口项目,第一件事不是写代码,是找数据。我见过不少新手上来就撸分类模型,结果数据一塌糊涂,最后debug的时间比写代码还长。说白了,数据探索就像盖房子打地基——你不想在二楼才发现一楼是歪的。

这一章,咱们就拿两个最经典的公开数据集练手:Iris 和 Titanic。一个干净得像教科书,另一个到处是坑。我会带着你一步步走完“获取 → 加载 → 扫一眼 → 画图 → 分析分布”这条线。相信我,做完这步,你的分类接口才真正有了灵魂。

公开数据集从哪搞?

我个人习惯首选 scikit-learn 内置的玩具数据集,比如 Iris。一条代码就能拉回来,不用注册、下载、解压,省心。

推荐来源:

  • scikit-learn 自带数据集:load_iris、load_wine、load_breast_cancer
  • Seaborn 内置数据集:titanic、penguins、tips
  • Kaggle 开源数据(需要 API 或手动下载)

为什么先推荐 Iris 和 Titanic?我自己的经验是:Iris 无缺失值、无异常值,特征连续且少,适合第一步练手;Titanic 呢,有缺失、有类别、有文本,几乎真实项目里你会遇到的脏东西它都有。一甜一苦,搭着学最稳。

用代码把数据拉进来

# 加载 Iris
from sklearn.datasets import load_iris
import pandas as pd

iris = load_iris()
df_iris = pd.DataFrame(iris.data, columns=iris.feature_names)
df_iris['target'] = iris.target
print(df_iris.head())
# 加载 Titanic
import seaborn as sns

df_titanic = sns.load_dataset('titanic')
print(df_titanic.head())

嗯,这里要注意:Seaborn 的 titanic 是轻量版,只有 891 行,但缺失值一个不少。我刚开始接真实项目时,负责一个用户行为分类的接口,数据比 Titanic 脏十倍——日期格式乱、性别字段有 6 种写法。当时我就后悔没在学阶段把清洗练熟。

初步探索:扫一眼长什么样

数据加载后别急着画图。先看看形状、列名、缺失情况、基本统计量。这一步我用一个 DataFrame 的 info() 和 describe() 搞定。

数据集样本数特征数缺失值目标类别
Iris150403
Titanic89115age(177), embarked(2), deck(688)survived (0/1)

看到 Titanic 的 deck 列缺了 688 个了吗?我曾经在一个电商订单接口里发现类似的问题——“支付渠道”字段 70% 为空,生产环境直接导致模型跑飞。所以,探索阶段首要任务就是标记缺失。

不要把缺失值直接扔掉。先想想:是随机缺失,还是与目标变量相关?Titanic 的 age 缺失与舱位等级有关——头等舱年龄记录更全。我后来做客户流失分类时,就因为这个认知偏差吃了亏。

画图:一图胜千言,一丑图也能暴露问题

我个人喜欢先用 Seaborn 的 pairplot 看 Iris——四个特征的散点矩阵,一眼就能看出 Setosa 线性可分,其他两类有重叠。这直接暗示了建模策略:对 Setosa 可以上简单阈值,对后两类最好用非线性模型。

Titanic 呢?我会画三张图:

  • 生存与性别:堆叠柱状图,女性生存率碾压男性
  • 年龄分布:直方图 + KDE,看存活/死亡的两个峰
  • 舱位与生存:箱线图或分面柱状图,头等舱胜率高

你想想看,这些发现直接决定了分类接口里要选哪些特征。我当年给一个保险公司做理赔分类,画图时发现“出险时间”分布有两个高峰——上午 10 点和下午 3 点,实际上那是报案电话的呼叫高峰,跟是否理赔无关。要不是先画了图,就引入噪声了。

画图不是为了好看,是为了产生假设。比如 Titanic 中年龄分布有两个峰值,我就怀疑:是否需要将年龄离散化为“儿童/成人/老人”?这个经验我在客户生命周期预测里反复用过。

# 快速画图示例(在 Jupyter 中运行)
import matplotlib.pyplot as plt
import seaborn as sns

sns.pairplot(df_iris, hue='target', diag_kind='kde')
plt.show()

sns.countplot(data=df_titanic, x='sex', hue='survived')
plt.show()

为什么我所有项目都坚持先画图?因为数据里藏着你意想不到的“模式”。有一次我做一个金融交易分类,画散点图发现交易金额和频次之间有个弯弯的倒 U 形——后来才知道那是风控规则导致的截断效应。代码跑十几遍都不如这张图来得直接。

特征分布初步分析:别只盯着平均值

描述性统计只是一个起点。这里我一个一个讲。

特征分布形状潜在问题对接口的影响
Iris sepal length单峰,近似正态三类有重叠需要组合其他特征
Iris petal length双峰Setosa 明显分离可作为强区分特征
Titanic age右偏,有少量老龄缺失 20%需插补或分桶
Titanic fare严重右偏异常高票价建议对数变换

你看,Iris 的 petal length 分布是双峰,意味着这个特征天然可以分两组。而 fate 严重右偏,如果你直接给分类接口送入原始数值,模型会被那几个高价票带偏。这类问题,探索阶段不解决,到调参时哭都来不及。

我曾经在构建一个电商订单分类接口时,特征“单笔金额”右偏得像火箭,结果模型死活不收敛。后来 log1p 变换,AUC 从 0.68 跳到 0.83。整个过程痛苦的根源就是——我当初没画分布图。

一张图串起整个探索流程

下面这张 SVG 把这一章的核心逻辑画出来了。你照着这张路线走,至少不会在茫茫特征里迷路。

数据收集与探索流程 ① 获取公开数据 ② 加载 & 初探 ③ 数据可视化 ④ 特征分布分析 ⑤ 形成探索结论 💡 关键产出 ▸ 缺失/异常标记 ▸ 分布形状 & 偏度 ▸ 特征-目标关联 ▸ 变换策略建议

流程总结一下:先拿到数据,快速加载看看头尾和缺失;然后画图检验直觉;再分析每个特征的分布形态;最后输出一个清晰的结论——哪些特征可以直接用,哪些需要清洗,哪些要变换。我自己每个项目都保持着“先画图再建模型”的习惯,十年了没断过。

一个小小的避坑指南

  • 别只打印 .head() 就以为看全了。 我犯过这错:一个用户年龄字段 head() 看起来都是正常值,但 tail() 有很多 0 和负数。最好 .describe() 先扫一遍 min 和 max。
  • 缺失值处理没银弹。 我在 Titanic 的 age 上用均值填充,结果头等舱儿童的年龄被成年均值拉高了。后来改用分组中位数填充才合理。所以,看着分布去处理。
  • 可视化不是一次性搞定。 先画全貌,发现问题再放大局部。我经常在画完 pairplot 后,单独针对某两个特征画 jointplot 细看。

写到这儿,你应该能感受到:数据探索不是枯燥的统计课,更像侦探找线索。有了这些线索,你的分类接口才能“对症下药”。下个阶段咱们就可以开始构造特征了——不过先别急,手动写完这一步的探索记录,才是真学到手。