AI: 数据基础
最后更新:2026-08-26
数据是 AI 的燃料——没有数据,再好的算法也训练不出好模型。本章帮你理解数据的类型、特征工程、数据集划分,以及"Garbage In, Garbage Out"的铁律。
1. 你将学到
- 数据在 AI 中的核心角色
- 结构化 vs 非结构化数据
- 特征(Feature)与标签(Label)
- 数据集划分:训练 / 验证 / 测试
- 数据质量如何影响 AI 性能
2. 一个机器学习项目的真实故事
(1) 痛点:训练一个月,准确率 60%
Bob 的团队花了一个月训练图像分类模型,准确率只有 60%。排查后发现:训练数据中 70% 是晴天图片,而实际应用场景包含各种天气——雨天、雾天、夜间。模型"没见过"这些情况,自然无法识别。
(2) 数据驱动的解法
Charlie 说:"这就是 Garbage In, Garbage Out——AI 只能学到你给它的东西。与其调算法参数,不如先修复数据分布。"
▶ 示例:检查数据分布——发现数据偏斜(难度⭐⭐)
PYTHON
# Check data distribution — first step before any AI project
import pandas as pd
df = pd.DataFrame({
'weather': ['sunny'] * 70 + ['rainy'] * 15 + ['foggy'] * 10 + ['night'] * 5,
'label': ['car'] * 50 + ['car'] * 5 + ['car'] * 3 + ['car'] * 2 +
['truck'] * 20 + ['truck'] * 10 + ['truck'] * 7 + ['truck'] * 3
})
print("Weather distribution:")
print(df['weather'].value_counts())
print(f"\nSunny images: {70/100*100:.0f}% — That's a problem!")
💻 输出:
TEXT
📖 仅展示
Weather distribution:
sunny 70
rainy 15
foggy 10
night 5
Name: weather, dtype: int64
Sunny images: 70% — That's a problem!
(3) 收益:数据先行意识
Bob 补充了各天气的图片后,准确率从 60% 提升到 85%。他总结出一条铁律:"调模型不如调数据"。
3. 数据的类型
(1) 按结构分类
| 类型 | 说明 | 示例 | AI 处理方式 |
|---|---|---|---|
| 结构化 | 有固定格式(行列表) | CSV、SQL 表、Excel | 直接输入传统 ML 模型 |
| 半结构化 | 有部分结构但格式灵活 | JSON、XML、HTML、日志 | 提取字段后输入模型 |
| 非结构化 | 无固定格式 | 图片、音频、视频、自然语言 | 深度学习(CNN/RNN/Transformer) |
(2) 按数值类型分类
| 类型 | 说明 | 示例 | 模型处理 |
|---|---|---|---|
| 数值型 | 连续或离散的数字 | 价格、面积、年龄 | 直接使用 |
| 类别型 | 有限个离散值 | 性别、城市、职业 | 需编码(One-Hot) |
| 文本型 | 自然语言字符串 | 评论、邮件正文 | 需向量化(Embedding) |
| 时间型 | 日期时间 | 下单时间、日志时间 | 需提取特征(年/月/小时) |
4. 特征与标签
特征(Feature)是模型的输入,标签(Label)是模型要预测的目标。
graph LR
A[Feature 1<br/>Area 120 sqm] --> C[AI Model]
B[Feature 2<br/>Rooms 4] --> C
D[Feature 3<br/>Location Score 8] --> C
C --> E[Label<br/>Price $350,000]
(1) 什么是特征
特征就是数据中"对预测有帮助"的属性:
| 数据集 | 可能的特征 | 标签 |
|---|---|---|
| 房价数据 | 面积、房间数、地段评分、楼层 | 房屋价格 |
| 邮件数据 | 发件人、关键词频率、附件数 | 是否垃圾邮件 |
| 用户数据 | 年龄、浏览次数、购买记录 | 是否会购买 |
| 图像数据 | 像素值(深度学习自动提取特征) | 图片类别 |
(2) 特征工程——手工打造 vs 自动提取
▶ 示例:手动特征工程——从文本提取特征(难度⭐⭐)
PYTHON
# Example: Manual feature engineering
import pandas as pd
df = pd.DataFrame({
'text': ['Free iPhone winner!', 'Meeting at 3pm', 'URGENT: Claim now'],
'label': ['spam', 'ham', 'spam']
})
# Manual feature extraction: count specific words
df['has_free'] = df['text'].str.lower().str.contains('free').astype(int)
df['has_urgent'] = df['text'].str.lower().str.contains('urgent').astype(int)
df['exclamation_count'] = df['text'].str.count('!')
df['text_length'] = df['text'].str.len()
print(df)
💻 输出:
TEXT
📖 仅展示
text label has_free has_urgent exclamation_count text_length
0 Free iPhone winner! spam 1 0 1 19
1 Meeting at 3pm ham 0 0 0 14
2 URGENT: Claim now spam 0 1 0 17
💡 提示: 传统 ML 需要人工设计特征(特征工程),深度学习则能自动从原始数据中学习特征。这是深度学习革命的核心优势之一。
5. 数据集划分
训练 AI 模型时,数据必须分成互不重叠的三个集合:
graph TB
A[Full Dataset<br/>1000 samples] --> B[Training Set<br/>800 samples<br/>80%]
A --> C[Validation Set<br/>100 samples<br/>10%]
A --> D[Test Set<br/>100 samples<br/>10%]
B --> E[Train the model]
C --> F[Tune hyperparameters]
D --> G[Final evaluation<br/>never used during training]
| 集合 | 作用 | 比例 | 关键规则 |
|---|---|---|---|
| 训练集 | 训练模型(学习参数) | 60-80% | 模型直接从中学习 |
| 验证集 | 调整超参数(选择最佳配置) | 10-20% | 间接影响模型,但不直接学习 |
| 测试集 | 最终评估(报告性能) | 10-20% | 训练过程中绝对不能使用 |
(1) 用 Python 划分数据集
▶ 示例:训练集/验证集/测试集的划分(难度⭐⭐)
PYTHON
# Split dataset into train/validation/test sets
from sklearn.model_selection import train_test_split
import pandas as pd
# Sample dataset
df = pd.DataFrame({
'area_sqm': [50, 80, 120, 65, 200, 90, 55, 110, 75, 150,
60, 85, 130, 95, 180, 70, 100, 45, 140, 105],
'price_usd': [150000, 280000, 350000, 220000, 500000, 260000,
165000, 320000, 240000, 420000, 175000, 270000,
380000, 290000, 460000, 210000, 300000, 135000,
400000, 310000]
})
# First split: 80% train+val, 20% test
train_val, test = train_test_split(df, test_size=0.2, random_state=42)
# Second split: 75% of train_val = 60% total train, 25% = 20% total val
train, val = train_test_split(train_val, test_size=0.25, random_state=42)
print(f"Full dataset: {len(df)} samples")
print(f"Training set: {len(train)} samples ({len(train)/len(df)*100:.0f}%)")
print(f"Validation set:{len(val)} samples ({len(val)/len(df)*100:.0f}%)")
print(f"Test set: {len(test)} samples ({len(test)/len(df)*100:.0f}%)")
💻 输出:
TEXT
📖 仅展示
Full dataset: 20 samples
Training set: 12 samples (60%)
Validation set:4 samples (20%)
Test set: 4 samples (20%)
⚠️ 注意: 测试集在训练过程中绝对不能使用。如果模型"看过"测试集的数据,评估结果就不客观——就像考试前看过答案再考试,分数不能反映真实水平。
6. 数据质量——Garbage In, Garbage Out
数据质量直接决定 AI 性能的上限。算法再好,也救不了坏数据:
| 质量问题 | 说明 | 影响 | 检测方法 |
|---|---|---|---|
| 缺失值 | 某些字段为空 | 模型无法处理缺失输入 | df.isnull().sum() |
| 重复数据 | 同一记录出现多次 | 模型对重复样本过度拟合 | df.duplicated().sum() |
| 类别偏斜 | 某类样本远多于其他类 | 模型偏向多数类 | df[label].value_counts() |
| 噪声/错误 | 数据值明显不合理 | 模型学到错误模式 | 统计异常值检测 |
| 标签错误 | 标注不正确 | 模型学到错误映射 | 人工抽检 |
(1) 检测数据质量问题
▶ 示例:数据质量检查报告(难度⭐⭐)
PYTHON
# Data quality check checklist
import pandas as pd
import numpy as np
df = pd.DataFrame({
'age': [25, 30, np.nan, 45, 200, 28, 30, 30, 35, np.nan],
'income': [50000, 60000, 45000, np.nan, 80000, 55000, 60000, 62000, 70000, 48000],
'label': ['buy', 'no', 'buy', 'no', 'buy', 'no', 'no', 'no', 'buy', 'no']
})
print("=== Data Quality Report ===")
print(f"Total rows: {len(df)}")
print(f"\nMissing values per column:")
print(df.isnull().sum())
print(f"\nDuplicate rows: {df.duplicated().sum()}")
print(f"\nLabel distribution:")
print(df['label'].value_counts())
print(f"\nSuspicious values (age > 120):")
print(df[df['age'] > 120])
💻 输出:
TEXT
📖 仅展示
=== Data Quality Report ===
Total rows: 10
Missing values per column:
age 2
income 1
label 0
dtype: int64
Duplicate rows: 0
Label distribution:
no 6
buy 4
Name: label, dtype: int64
Suspicious values (age > 120):
age income label
4 200 80000 buy
💡 提示: age=200 明显是错误数据。这种异常值如果不清理,模型会"学习"到"200 岁的人会购买"这种荒谬规则。
7. 常见公开数据集
做 AI 实验不一定需要自己收集数据,很多高质量公开数据集可以直接使用:
| 数据集 | 任务 | 样本数 | 特点 |
|---|---|---|---|
| Iris | 分类 | 150 | 最简单的 ML 入门数据集 |
| Titanic | 分类 | 891 | Kaggle 经典入门赛题 |
| MNIST | 图像分类 | 70,000 | 手写数字,CV 入门 |
| CIFAR-10 | 图像分类 | 60,000 | 10 类彩色图片,比 MNIST 更难 |
| California Housing | 回归 | 20,640 | 加州房价预测 |
| IMDB Reviews | 情感分析 | 50,000 | 电影评论正/负分类 |
8. 完整示例:Titanic 数据准备流水线
在 Titanic 数据集上完成数据概览 → 缺失值检查 → 类别分布统计 → 划分训练/测试集,形成完整的"数据准备流水线":
▶ 示例:Titanic 数据准备完整流水线(难度⭐⭐⭐)
PYTHON
# ============================================
# Complete Data Preparation Pipeline
# Dataset: Titanic (simulated)
# ============================================
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
# Simulated Titanic-like dataset
np.random.seed(42)
df = pd.DataFrame({
'pclass': np.random.choice([1, 2, 3], 100, p=[0.2, 0.3, 0.5]),
'sex': np.random.choice(['male', 'female'], 100, p=[0.6, 0.4]),
'age': np.where(np.random.rand(100) > 0.15,
np.random.randint(1, 80, 100), np.nan),
'fare': np.round(np.random.uniform(10, 500, 100), 2),
'survived': np.random.choice([0, 1], 100, p=[0.6, 0.4])
})
# Step 1: Overview
print("=== Step 1: Data Overview ===")
print(f"Shape: {df.shape}")
print(df.head(5))
# Step 2: Missing values
print("\n=== Step 2: Missing Values ===")
missing = df.isnull().sum()
missing_pct = (df.isnull().sum() / len(df) * 100).round(1)
print(pd.DataFrame({'count': missing, 'percent': missing_pct}))
# Step 3: Label distribution
print("\n=== Step 3: Label Distribution ===")
print(df['survived'].value_counts())
print(f"Survival rate: {df['survived'].mean()*100:.1f}%")
# Step 4: Train/test split
train, test = train_test_split(df, test_size=0.2, random_state=42,
stratify=df['survived'])
print(f"\n=== Step 4: Data Split ===")
print(f"Train: {len(train)} samples, survival rate: {train['survived'].mean()*100:.1f}%")
print(f"Test: {len(test)} samples, survival rate: {test['survived'].mean()*100:.1f}%")
print(f"\nStratified split ensures same survival rate in both sets!")
💻 输出:
TEXT
📖 仅展示
=== Step 1: Data Overview ===
Shape: (100, 5)
pclass sex age fare survived
0 3 female 47.0 339.89 1
1 3 female 63.0 361.38 0
2 1 female 44.0 309.18 0
3 3 male 28.0 385.59 0
4 1 male 8.0 477.95 0
=== Step 2: Missing Values ===
count percent
pclass 0 0.0
sex 0 0.0
age 14 14.0
fare 0 0.0
survived 0 0.0
=== Step 3: Label Distribution ===
0 58
1 42
Name: survived, dtype: int64
Survival rate: 42.0%
=== Step 4: Data Split ===
Train: 80 samples, survival rate: 42.5%
Test: 20 samples, survival rate: 40.0%
Stratified split ensures same survival rate in both sets!
❓ 常见问题
Q 数据量越大 AI 就越准吗?
A 不一定。数据质量比数量更重要。10K clean records may outperform 1 million noisy records for training a better model。关键维度:数据量、质量、多样性、代表性缺一不可。
Q 训练集和测试集为什么不能重叠?
A 因为测试集是用来评估模型"真实能力"的。如果模型在训练时"见过"测试集的数据,它就会记住答案而不是学会方法——这叫数据泄漏(Data Leakage),评估结果会虚高。
Q 什么是数据偏斜?怎么处理?
A 数据偏斜指不同类别的样本数量差异巨大(如 99% 正常 vs 1% 异常)。处理方法:① 收集更多少数类数据 ② 过采样少数类(SMOTE)③ 欠采样多数类 ④ 调整类别权重 ⑤ 使用 F1 而非准确率评估。
Q 特征工程是什么?为什么要做?
A 特征工程是从原始数据中提取/构造对预测有帮助的新特征的过程。比如从"下单时间"提取"是否周末"、"是否夜间"等特征。好的特征工程可以让简单模型达到复杂模型的效果,在传统 ML 中非常关键。深度学习能自动做特征提取,减少了人工特征工程的需求。
Q 哪里可以找到免费的数据集?
A Kaggle(kaggle.com/datasets)、UCI Machine Learning Repository、Google Dataset Search、Hugging Face Datasets、政府开放数据平台。本教程使用 sklearn 自带数据集,无需额外下载。
Q 什么是 stratified split(分层划分)?
A 普通随机划分可能导致训练/测试集中类别比例不一致。Stratified split 保证各集合中类别比例与原始数据一致。对于偏斜数据集(如 90% vs 10%),stratified split 几乎是必须的。
📖 小节
- 数据是 AI 的燃料,没有高质量数据就没有好模型——Garbage In, Garbage Out
- 数据分三类:结构化(表格)、半结构化(JSON/XML)、非结构化(图片/文本/音频)
- 特征是模型输入,标签是模型要预测的目标;特征工程是传统 ML 的核心技能
- 数据集必须划分为训练集 / 验证集 / 测试集,测试集在训练过程中绝对不能使用
- 数据质量问题(缺失/重复/偏斜/噪声/标签错误)必须在上游解决,调模型救不了坏数据
- 公开数据集(Iris/Titanic/MNIST)是 AI 入门的最佳起点
📝 作业
- 基础题(难度⭐):用 Python 加载一个 CSV 数据集(或 sklearn 自带数据集),用
df.info()和df.describe()统计基本信息。 - 进阶题(难度⭐⭐):检查数据中的缺失值和类别分布,画出某列的分布直方图(提示:
df[column].hist())。 - 挑战题(难度⭐⭐⭐):用
train_test_split按 80/20 划分数据,对比普通划分和 stratified 划分后类别比例是否一致。