Skip to content

数据工具链:NumPy / Pandas / 可视化 ​

目标:拿到一份陌生 CSV,能在 2 小时内产出可行动的结论。

这是 AI 从业者使用频率最高的技能。模型可以换,数据处理每天都要做。

三件套的分工 ​

工具负责心智模型
NumPy数值数组、向量化计算「一整块数字」
Pandas表格、索引、分组聚合、清洗「带行标列标的 Excel」
Matplotlib / Seaborn可视化「用图说服人」

原则:能用向量化就别写 for 循环,差 10–100 倍性能。

一、NumPy:向量化思维 ​

python
import numpy as np

# 创建
a = np.array([1, 2, 3])
z = np.zeros((2, 3)); o = np.ones(5); r = np.random.randn(3, 4)
seq = np.arange(0, 10, 2); lin = np.linspace(0, 1, 5)

# 形状操作
x = np.random.randn(32, 128, 768)      # (batch, seq, dim)
print(x.reshape(32, -1).shape)          # (32, 98304)  -1 自动推断
print(x.transpose(0, 2, 1).shape)       # (32, 768, 128)
print(x[0].shape, x[:, 0].shape)        # (128,768) (32,768)  切片

# 统计(指定 axis 是关键)
print(x.mean(axis=0).shape)             # (128,768) 对 batch 求均值
print(x.mean(axis=(0, 1)).shape)        # (768,)   压平 batch 与 seq

# 向量化:一次算完,比 for 快几十倍
data = np.random.randn(1000000)
print((data ** 2).mean())               # 全量平方再平均

# 广播
X = np.random.randn(100, 5)
mu, sd = X.mean(0), X.std(0)            # (5,) (5,)
X_norm = (X - mu) / (sd + 1e-8)         # (100,5),自动广播

三个最常用的习惯

  1. axis 想清楚:axis=0 是「跨行压缩」,结果是列数
  2. + 1e-8:除法前永远加个极小值,避免除零产出 nan
  3. reshape(-1, ...):不确定维度就交给 -1

二、Pandas:80% 的数据工作 ​

加载与初看 ​

python
import pandas as pd

df = pd.read_csv("data.csv")
# 大文件/中文编码问题:pd.read_csv("data.csv", encoding="utf-8-sig")
# 只要部分列:pd.read_csv("data.csv", usecols=["id","price","label"])

print(df.shape)          # (行数, 列数)
print(df.head(3))        # 前 3 行
print(df.info())         # 类型 + 缺失情况 —— 第一眼必看
print(df.describe())     # 数值列统计
print(df["label"].value_counts())   # 类别分布 —— 第二眼必看

加载后 30 秒内必须看的三件事:shape、info()(有没缺失)、value_counts()(类别是否失衡)。

选择与过滤 ​

python
df["price"]                       # 一列 → Series
df[["id", "price"]]               # 多列 → DataFrame
df.loc[0, "price"]                # 按标签
df.iloc[0, 2]                     # 按位置
df[df["price"] > 100]             # 布尔过滤
df[(df["price"] > 100) & (df["city"] == "上海")]   # 与用 &,或 |,每个条件加括号
df.query("price > 100 and city == '上海'")         # 更可读的写法

清洗:真实工作的 70% ​

python
# 1. 缺失值:先量化再决策
df.isna().mean().sort_values(ascending=False)     # 每列缺失率

df["age"] = df["age"].fillna(df["age"].median())  # 数值:中位数(比均值抗异常)
df["city"] = df["city"].fillna("未知")            # 类别:单独一类,别丢信息
df = df.dropna(subset=["label"])                  # 标签缺失的样本必须删

# 2. 类型转换
df["price"] = pd.to_numeric(df["price"], errors="coerce")   # 脏值变 NaN
df["date"] = pd.to_datetime(df["date"], errors="coerce")

# 3. 去重
df = df.drop_duplicates(subset=["user_id", "date"])

# 4. 类别编码
df["city_code"] = df["city"].astype("category").cat.codes   # 省内存
# 或用 one-hot(类别少时)
df = pd.get_dummies(df, columns=["city"], prefix="city")

缺失值三种处理,选错会毁掉模型

方式何时用风险
删除行缺失率极低(<1%)有偏采样
填充统计量数值型、缺失随机低估方差
填充「未知」类别型无风险,推荐
填充目标均值❌ 绝对不要数据泄漏

分组聚合:数据分析的核心动作 ​

python
# 单维度
print(df.groupby("city")["price"].agg(["count", "mean", "median", "max"]))

# 多维度 + 多指标
summary = df.groupby(["city", "category"]).agg(
    orders=("order_id", "count"),
    revenue=("price", "sum"),
    avg_price=("price", "mean"),
).reset_index()

# 透视表(交叉分析)
print(pd.pivot_table(df, index="city", columns="category",
                     values="price", aggfunc="mean", fill_value=0))

# 时间序列
df["month"] = df["date"].dt.to_period("M")
print(df.groupby("month")["price"].sum())

合并 ​

python
# 左连接:以左表为主
merged = orders.merge(users, on="user_id", how="left")
# 合并前必查:主键是否唯一,否则行数会翻倍
print(users["user_id"].duplicated().sum())

三、可视化:让结论一眼可见 ​

python
import matplotlib.pyplot as plt
import seaborn as sns

plt.rcParams["font.sans-serif"] = ["PingFang SC", "Microsoft YaHei", "SimHei"]
plt.rcParams["axes.unicode_minus"] = False      # 负号显示

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

# ① 数值分布
sns.histplot(df["price"], bins=40, kde=True, ax=axes[0])
axes[0].set_title("价格分布")

# ② 类别对比
sns.boxplot(data=df, x="city", y="price", ax=axes[1])
axes[1].set_title("各城市价格对比")

# ③ 相关性
sns.heatmap(df.select_dtypes("number").corr(),
            annot=True, fmt=".2f", cmap="RdBu_r", center=0, ax=axes[2])
axes[2].set_title("特征相关性")

plt.tight_layout()
plt.savefig("eda.png", dpi=150)

按目的选图 ​

你想说明用什么图
单变量分布直方图、KDE、箱线图
类别间比较箱线图、条形图、小提琴图
两个变量的关系散点图(量大用 hexbin / 抽样)
相关性全貌热力图
时间趋势折线图
占比构成堆叠条形图(少用饼图)
失衡程度频次条形图(对数 y 轴)

四、一个完整的最小 EDA 流程 ​

python
def quick_eda(path: str, target: str | None = None) -> pd.DataFrame:
    df = pd.read_csv(path)
    print(f"形状: {df.shape}")

    report = pd.DataFrame({
        "dtype": df.dtypes.astype(str),
        "missing%": (df.isna().mean() * 100).round(2),
        "n_unique": df.nunique(),
    })
    print("\n--- 列画像 ---")
    print(report.sort_values("missing%", ascending=False).head(20))

    if target and target in df.columns:
        print(f"\n--- 目标 {target} 分布 ---")
        print(df[target].value_counts(normalize=True).round(3))
        if df[target].nunique() < 10:
            print(f"失衡比: {df[target].value_counts().max() / df[target].value_counts().min():.2f}")

    num = df.select_dtypes("number")
    if num.shape[1] > 1:
        print("\n--- 与目标相关性 Top5 ---")
        if target in num.columns:
            print(num.corr()[target].abs().sort_values(ascending=False).head(5))
    return report

quick_eda("titanic.csv", target="Survived")

五、性能与常见坑 ​

场景做法
文件很大(>1GB)dtype 指定类型、usecols 只读需要列、分块 chunksize
内存不够pd.read_csv(..., low_memory=False) 排除类型推断问题,或改 Parquet
循环太慢换成 groupby / apply / 向量化
SettingWithCopyWarning用 .loc 赋值:df.loc[df.a > 1, "b"] = 0
合并后行数暴涨检查主键重复
中文乱码encoding="utf-8-sig"

通过标准 ​

下一步 ​

→ L2 机器学习:把干净的数据变成会预测的模型

AI 学习路线 · 从入门到专家