🗄️ Stage 02 · 数据工程

数据是AI的燃料

数据工程 = 收集 → 质检与初筛 → 数据标注。数据质量决定模型上限,上游每省1小时,下游省10倍时间。

🔄 数据工程完整流水线(3 步)

从原始数据到可标注数据集——"及格线检查",深度清洗和标准化在下游预处理完成

1
📥
STEP 1
数据收集
爬虫/开源/设备/合成
2
🔍
STEP 2
质检与初筛
去重/补缺/剔坏样本
3
🏷️
STEP 3
数据标注
分类/检测/分割/NLP

📥 Step 1:数据收集全方案

数据收集是整个流水线的起点——没有好数据,再好的模型也白搭。核心问题:从哪来?够不够?合不合法?

📚

开源数据集

▸适用场景:计算机视觉、NLP、语音、推荐系统等通用任务
▸热门仓库:HuggingFace 🤗、Kaggle、UCI ML、Open Images、Common Voice
▸关键注意:检查数据许可证(CC / MIT / 商业限制)、评估数据偏差
🕷️

网络爬虫采集

▸适用场景:公开网页数据、电商评论、新闻文本、社交媒体
▸技术栈:Requests + BeautifulSoup / Selenium / Scrapy / Playwright
▸关键注意:遵守 robots.txt、控制请求频率、处理反爬机制
# 最简爬虫示例
import requests
from bs4 import BeautifulSoup

resp = requests.get("https://example.com")
soup = BeautifulSoup(resp.text, "html.parser")
items = soup.select(".product")  # CSS 选择器
🔌

官方 API 接口获取

▸适用场景:需要实时数据、结构化 JSON 数据、官方权威数据源
▸热门 API:Twitter/X API、YouTube Data、TMDB 电影、Alpha Vantage 股票、OpenWeather、GitHub REST
▸关键注意:API 限流速率、认证鉴权(API Key / OAuth)、请求成本、数据使用条款
# 调用 TMDB 官方 API 获取电影数据
import requests

API_KEY = "your_tmdb_api_key"
url = "https://api.themoviedb.org/3/discover/movie"
params = {"api_key": API_KEY, "sort_by": "popularity.desc"}
resp = requests.get(url, params=params)
data = resp.json()  # 返回结构化 JSON
🎛️

人工合成数据

▸适用场景:真实数据稀缺、极端场景模拟、数据隐私敏感
▸方法:GAN 生成图像、3D 引擎渲染、SMOTE 过采样、规则生成文本
▸关键注意:合成数据分布偏差、需要真实数据做验证
# SMOTE 合成少数类样本
from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state=42)
X_new, y_new = smote.fit_resample(X, y)
📡

传感器/设备采集

▸适用场景:物联网、医疗监测、工业质检、自动驾驶
▸数据类型:温度/湿度/振动时序、摄像头图像、LiDAR 点云、ECG 信号
▸关键注意:时间同步、设备校准、噪声过滤、隐私合规
📷
摄像头
📏
LiDAR
💓
生物信号

🧭 数据源选择决策树

1. 有现成数据?
优先查开源数据集,省时间省成本
2. 需要特定场景?
自己爬/采,但注意合规
3. 数据量不够?
合成 + 数据增强补充
4. 有隐私顾虑?
合成数据优先 / 脱敏处理

🔍 Step 2:数据质检与初筛

数据工程环节的质检与初筛:去重、补缺、剔除坏样本、格式核验——深度标准化、特征工程、数据集划分等在下游数据预处理阶段完成

📊 表格数据质检

结构化数据 / CSV / 数据库表 · Pandas 为主

🆔主键/重复检测
主键列重复行 + 全表重复数据行
手机号重复 × 2 组(keep=False 共 4 行) · 整行重复 × 1 组(共 2 行)
🕳️缺失值检测
空值统计(NaN / 空字符串 / 占位符 - 、N/A)
年龄列缺失 × 2 · 手机号缺失 × 2 · 注册日期缺失 × 1
🔢数值范围/异常
业务范围校验 + 3σ / IQR 统计异常值
年龄范围外 × 1(-45)· 金额异常 × 0
📐格式/类型校验
正则匹配 + dtype 推断 + 日期解析
手机号非法 × 1 · 日期格式错误 × 1

🎯 交互式演练:质检一份脏数据

下面是一份带有问题的客户数据,请点击每个"问题行"查看清洗逻辑:

ID 姓名 年龄 手机号 注册日期 金额 操作
001张三28138001380012024-01-155000✓ 正常
002李四32139123456782024-02-208000⚠️ 主键重复
002李四32139123456782024-02-208000⚠️ 主键重复
003王五 137987654322024-03-106500⚠️ 缺失值
004赵六-45136000011112024-04-059200⚠️ 负值异常
005钱七24123452024-05-123800⚠️ 手机号短
006孙八30135555566662024-06-187100✓ 正常
007周九27188123456782024-13-405600⚠️ 日期非法
008吴十 139998877662024-08-158900⚠️ 缺失值
009郑十一29159000011112024-09-014200✓ 正常
010冯十二999136123456782024-10-1010500⚠️ 超龄异常
011陈十三33invalid_phone2024-11-056300⚠️ 手机号非法
012褚十四27137111122222024-12-127800✓ 正常
013卫十五 138888899992025-01-205100⚠️ 缺失值
014蒋十六38135000099992025-02-289400✓ 正常
002李四32139123456782024-02-208000⚠️ 主键重复(第三次出现)
015沈十七-100136123400002025-03-157200⚠️ 负值异常
016韩十八411234567890123452025-04-016000⚠️ 手机号过长

🛠️ 一键运行:完整表格数据质检与初筛 Pipeline

import pandas as pd
import numpy as np

# ═══════════════════════════════════════════
# 一键运行:完整表格数据质检 + 初筛 Pipeline
# 覆盖 4 张卡片:主键重复 · 缺失值 · 数值异常 · 格式校验
# ═══════════════════════════════════════════

# ====== Step 0: 读取数据 ======
df = pd.read_csv("dirty_data.csv", dtype={"手机号": str})
# encoding="gbk", dtype={"手机号": str}  ← Windows 中文 CSV 加 encoding
print(f"原始数据 {len(df)} 行 × {len(df.columns)} 列")
print("=" * 50)

# ============================================================
# 第一阶段:质检检测(只检测不改数据,输出完整报告)
# ============================================================
print("📋 【质检报告】")

# ====== ① 主键/重复检测 ======
print("\n① 🆔 主键/重复检测")
df["手机号"] = df["手机号"].astype(str).str.strip()
dup_key = df[df.duplicated(subset=["手机号"], keep=False)]
dup_row = df[df.duplicated(keep=False)]
print(f"   手机号重复: {len(dup_key)} 行  整行重复: {len(dup_row)} 行")

# ====== ② 缺失值检测 ======
print("\n② 🕳️ 缺失值检测(NaN / 空串 / 占位符)")
PLACEHOLDERS = ["", "-", "N/A", "null"]
missing_report = {}
for col in df.columns:
    n = df[col].isna().sum() + df[col].astype(str).str.strip().isin(PLACEHOLDERS).sum()
    if n > 0:
        missing_report[col] = n
        print(f"   {col}: {n} 处缺失")
missing_total = sum(missing_report.values())
print(f"   全表缺失率: {missing_total / df.size * 100:.1f}%")

# ====== ③ 数值异常检测(业务范围 + 3σ + IQR) ======
print("\n③ 🔢 数值异常检测")
NUM_COLS = ["年龄", "金额"]
RANGE = {"年龄": (0, 120), "金额": (0, 1e7)}
for col in NUM_COLS:
    if col not in df.columns: continue
    s = pd.to_numeric(df[col], errors="coerce")
    lo, hi = RANGE[col]
    biz = ((s < lo) | (s > hi)).sum()                           # 业务范围
    mu, sigma = s.mean(), s.std()
    sig3 = ((s - mu).abs() > 3 * sigma).sum()             # 3σ(Z-score 阈值 3)
    q1, q3 = s.quantile(0.25), s.quantile(0.75)
    iqr_lo, iqr_hi = q1 - 1.5*(q3-q1), q3 + 1.5*(q3-q1)
    iqr = ((s < iqr_lo) | (s > iqr_hi)).sum()                   # IQR(四分位法)
    print(f"   {col}: 业务范围 {biz} · 3σ/Z-score {sig3} · IQR {iqr}")

# ====== ④ 格式校验 ======
print("\n④ 📐 格式校验")
bad_phone = ~df["手机号"].str.match(r"^1[3-9]\d{9}$")
print(f"   手机号非法: {bad_phone.sum()} 行")
df["注册日期"] = df["注册日期"].astype(str).str.replace("/", "-", regex=False)
bad_dt = pd.to_datetime(df["注册日期"], errors="coerce").isna()
print(f"   日期格式错误: {bad_dt.sum()} 行")

print("\n" + "=" * 50)

# ============================================================
# 第二阶段:清洗修复(根据质检报告自动处理)
# ============================================================

# 1. 手机号非法 → 过滤(先过滤脏号再去重)
df = df[~bad_phone]

# 2. 主键/整行去重(keep="last" 保留最新)
df = df.drop_duplicates(subset=["手机号"], keep="last")
df = df.drop_duplicates(keep="first")  # 整行完全重复

# 3. 年龄:转数值 + 业务范围过滤
df["年龄"] = pd.to_numeric(df["年龄"], errors="coerce")
df = df[(df["年龄"] >= 0) & (df["年龄"] <= 120)]

# 4. 金额:IQR 异常裁剪(不直接丢,打 cap)
if "金额" in df.columns:
    df["金额"] = pd.to_numeric(df["金额"], errors="coerce")
    q1, q3 = df["金额"].quantile(0.25), df["金额"].quantile(0.75)
    lo, hi = q1 - 1.5*(q3-q1), q3 + 1.5*(q3-q1)
    df["金额"] = df["金额"].clip(lower=max(lo, 0), upper=hi)

# 5. 年龄缺失:median 填充(可改成 groupby 性别分组更准)
df["年龄"] = df["年龄"].fillna(df["年龄"].median())

# 6. 日期:统一分隔符 + 解析 + 打标(不 dropna)
df["注册日期"] = df["注册日期"].astype(str).str.replace("/", "-", regex=False)
df["注册日期"] = pd.to_datetime(df["注册日期"], errors="coerce")
df["日期缺失"] = df["注册日期"].isna()

# 7. 保存 + 最终报告
df.to_csv("cleaned_data.csv", index=False)
print(f"✅ 清洗完成:{len(df)} 行 → 已保存 cleaned_data.csv")

🏷️ Step 3:数据标注

标注是让数据"有意义"的关键步骤

📊

分类标注

给样本打类别标签(如:正面/负面/中性)

工具:Label Studio, Doccano
🚀 查看分类标注完整流程 →
🎯

检测标注

在图像上画框(bbox)标注物体位置

工具:LabelImg, CVAT, Roboflow
🚀 查看目标检测标注完整流程 →
🗺️

分割标注

像素级精确标注目标轮廓

工具:LabelMe, CVAT, Supervisely
🚀 查看语义分割标注完整流程 →
📝

NLP标注

实体识别、关系抽取、意图标注

工具:Doccano, Label Studio, Prodigy
🚀 查看文本序列标注完整流程 →

💰 标注成本估算器(交互式)

预估时间
-- 天
预估成本
-- 元
推荐方案
--
← 返回需求定义