CHAPTER 08

Pandas:数据处理与分析

AI 项目 80% 的时间花在数据处理上。Pandas 是处理表格数据的利器,从数据清洗到特征工程,它是 AI 数据管道的核心工具。

DataFrame —— 表格数据的核心

Pandas 最重要的结构是 DataFrame,本质上是一张带有行索引和列标签的二维表格,就像 Excel 表格,但能处理百万级数据且可编程。每一列是一个 Series

核心概念

DataFrame vs NumPy 数组

NumPy 数组的列是匿名的数字索引,所有数据必须同类型。DataFrame 的列有名字,不同列可以有不同类型(年龄是 int,姓名是 str,分数是 float)。这让它非常适合处理真实的 AI 训练数据集。

PYTHON · 创建 DataFrame
import pandas as pd
import numpy as np

# 从字典创建(最常用)
df = pd.DataFrame({
    "样本ID":    ["s001", "s002", "s003", "s004"],
    "年龄":      [25, 30, None, 22],   # None = 缺失值
    "收入":      [5000, 8000, 6000, 4500],
    "标签":      [1, 0, 1, 0],
})

# 查看基本信息
print(df)              # 打印整张表
print(df.shape)        # (4, 4) → 4行4列
print(df.dtypes)       # 各列的数据类型
print(df.info())       # 完整信息,含非空值数量
print(df.describe())  # 数值列的统计摘要(均值、标准差等)

# 从 CSV 读取(实际项目最常见)
df = pd.read_csv("train_data.csv")
df.to_csv("output.csv", index=False)  # 保存,不写行号

# 前/后几行预览
print(df.head(5))   # 前5行
print(df.tail(3))   # 后3行
print(df.sample(3)) # 随机3行

选取数据:loc 和 iloc

Pandas 有两种主要的数据选取方式:loc标签选取,iloc整数位置选取。分清这两者,是使用 Pandas 的关键。

PYTHON · 数据选取
df = pd.DataFrame({
    "feature1": [0.1, 0.5, 0.3, 0.8],
    "feature2": [1.2, 2.3, 0.9, 3.1],
    "label":    [0, 1, 0, 1]
})

# 选取列(单列返回 Series,多列返回 DataFrame)
labels   = df["label"]                    # Series
features = df[["feature1", "feature2"]]   # DataFrame

# loc:按标签选取行列
print(df.loc[0])              # 第0行(行索引是整数时)
print(df.loc[0:2])            # 第0-2行(包含第2行!)
print(df.loc[0, "feature1"])  # 第0行 feature1 列

# iloc:按整数位置选取
print(df.iloc[0])              # 第0行
print(df.iloc[:2, :2])         # 前2行前2列
print(df.iloc[-1])             # 最后一行

# 条件筛选(最常用!)
positive  = df[df["label"] == 1]           # 所有正样本
high_feat = df[df["feature2"] > 2.0]       # feature2 > 2 的行
multi     = df[(df["label"]==1) & (df["feature1"]>0.4)]
print(positive)

数据清洗

真实数据总是"脏的"——有缺失值、重复行、异常值。在送入模型前必须清洗,否则会严重影响训练效果。"垃圾进,垃圾出(Garbage In, Garbage Out)"是 AI 领域的著名定律。

PYTHON · 数据清洗
# 检查缺失值
print(df.isnull().sum())        # 每列缺失值数量
print(df.isnull().sum() / len(df))  # 缺失比例

# 处理缺失值
df_drop = df.dropna()           # 删除含缺失值的行
df_fill = df.fillna(0)          # 用0填充所有缺失值

# 按列填充(更好的做法)
df["年龄"] = df["年龄"].fillna(df["年龄"].mean())    # 用均值填充
df["类别"] = df["类别"].fillna(df["类别"].mode()[0])  # 用众数填充
df["值"]   = df["值"].fillna(method="ffill")            # 前向填充

# 删除重复行
df = df.drop_duplicates()
df = df.drop_duplicates(subset=["样本ID"])  # 按指定列去重

# 处理异常值(基于 3σ 原则)
col = "收入"
mean, std = df[col].mean(), df[col].std()
df = df[(df[col] >= mean - 3 * std) &
         (df[col] <= mean + 3 * std)]

# 重置行索引
df = df.reset_index(drop=True)

特征工程

特征工程是将原始数据转换为模型能更好学习的格式。好的特征工程常常比换一个更复杂的模型效果更显著。

PYTHON · 特征工程常用操作
# 1. 数值归一化(Min-Max Scaling)
for col in ["年龄", "收入"]:
    min_v = df[col].min()
    max_v = df[col].max()
    df[col] = (df[col] - min_v) / (max_v - min_v)

# 2. 类别编码(One-Hot Encoding)
df = pd.get_dummies(df, columns=["城市"], prefix="city")
# "北京", "上海", "广州" → city_北京, city_上海, city_广州(0或1)

# 3. 标签编码(Label Encoding)
df["性别_num"] = df["性别"].map({"男": 0, "女": 1})

# 4. 创建新特征(组合特征)
df["收入/年龄"] = df["收入"] / df["年龄"]
df["高收入"]  = (df["收入"] > 0.7).astype(int)

# 5. 时间特征提取
df["日期"] = pd.to_datetime(df["日期"])
df["月份"]   = df["日期"].dt.month
df["星期"]   = df["日期"].dt.dayofweek
df["是否周末"] = (df["星期"] >= 5).astype(int)
🤖

特征工程的黄金法则

神经网络理论上能自动学习特征,但提供好的特征仍然有帮助。对于结构化数据(表格),特征工程是关键。对于图像和文本,通常让模型自己学。pd.get_dummies() 是处理类别变量最常用的方法,面试必考。

groupby —— 分组聚合

groupby 是 Pandas 最强大的功能之一,类似 SQL 的 GROUP BY:按某列分组,再对每组做统计。在 AI 中用于按类别分析数据分布是否均衡。

PYTHON · groupby 聚合
df = pd.DataFrame({
    "类别": ["猫", "狗", "猫", "狗", "鸟", "鸟"],
    "得分": [0.8, 0.6, 0.9, 0.7, 0.5, 0.55],
    "置信度": [0.9, 0.7, 0.85, 0.75, 0.6, 0.65],
})

# 按类别分组,计算各列均值
print(df.groupby("类别").mean())

# 多种聚合函数同时计算
summary = df.groupby("类别")["得分"].agg(["mean", "std", "count"])
print(summary)

# 查看类别分布(AI 中用于检查数据是否均衡)
print(df["类别"].value_counts())
print(df["类别"].value_counts(normalize=True))  # 百分比

# 相关性分析(特征选择)
print(df.corr())  # 各数值列之间的相关系数矩阵

综合示例:完整数据预处理流程

PYTHON · AI 数据预处理全流程
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

# 1. 加载数据
df = pd.read_csv("titanic.csv")
print(f"原始数据: {df.shape}")

# 2. 查看缺失情况
print(df.isnull().sum())

# 3. 清洗
df["Age"]    = df["Age"].fillna(df["Age"].median())
df["Embarked"] = df["Embarked"].fillna(df["Embarked"].mode()[0])
df = df.drop(columns=["Cabin", "Ticket", "Name", "PassengerId"])

# 4. 特征工程
df["Sex"] = df["Sex"].map({"male": 0, "female": 1})
df = pd.get_dummies(df, columns=["Embarked"])
df["FamilySize"] = df["SibSp"] + df["Parch"] + 1

# 5. 分离特征和标签
X = df.drop(columns=["Survived"])
y = df["Survived"]

# 6. 切分训练集测试集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

print(f"训练集: {X_train.shape}, 测试集: {X_test.shape}")
print(f"正负样本比: {y_train.mean():.2%}")

这是 Kaggle 竞赛的标准流程

上面的泰坦尼克号数据集是机器学习入门的"Hello World"。这个预处理流程——读取→清洗→特征工程→切分——在几乎所有结构化数据的 AI 项目中都适用。