ML 学习站
跳到正文

数据类型与抽样设计

定量/分类、离散/连续、随机抽样与实验设计。

30 分钟2 / 42,983
加载中...

本章深入探讨了数据类型与抽样设计,核心概念包括数据分类四象限、测量尺度和抽样误差来源。数据分类四象限将数据分为定量、分类、离散和连续四类,并指出实际应用中常见的混淆,例如将排名、电话号码和年份误认为定量数据。测量尺度则细分为定类、定序、定距和定比四类,0 的绝对意义是区分定距和定比的关键。抽样误差来源于随机误差、抽样偏差和测量误差,需通过增加样本量、改进抽样设计和校准工具来控制。读者将学会区分不同数据类型和测量尺度,理解抽样误差的来源和量化方法,并掌握实验设计的三大原则:随机化、区组化和重复。这些知识将帮助读者在实际应用中选择合适的统计方法,设计有效的实验,并识别和减少数据偏差。

数据类型与抽样设计

本章问题: 为什么 sklearn 对"性别"列用 OneHotEncoder, 对"年龄"列用 StandardScaler? 因为它们是不同类型的数据。本章把"数据类型"讲透, 这是选统计方法的第一关

1. 数据分类四象限 (回顾 + 深入)

上一章我们把数据分成了 4 类:

  • 定量 (Quantitative): 数字, 可加减, 有单位
  • 分类 (Qualitative): 类别、标签、不能算平均
  • 离散 (Discrete): 整数、可数
  • 连续 (Continuous): 实数、不可数

但实务中, 这 4 类经常被混淆, 下面 3 个最常见的坑:

坑 1: "把排名当数字"

问卷结果: "请为这个商品打分 1-5"
得到的 "1, 2, 3, 4, 5" 看起来是数字
但本质是: 1=非常不满意, 5=非常满意 → 这叫"有序型分类"
→ 算 "平均分 3.8" 在数学上对, 但统计上"3.8"没有意义

坑 2: "把电话号码当数字"

手机号 13812345678 — 13 位数字, 但前 7 位是运营商 + 地区
→ 算"平均手机号" = 1.38e10 没有任何意义
→ 应该当"标签型分类"处理

坑 3: "把年份当连续"

2020, 2021, 2022, 2023 看起来是连续整数
但年份是"时间标签", 间距相等, 但加权和减权不总有意义
→ 业务上是时间序列数据, 不是简单连续定量

2. 测量尺度:从粗到精的 4 级

统计学家 Stanley Smith Stevens 提出了更精细的"测量尺度"分类:

尺度允许的运算例子中心趋势
定类 (Nominal)仅判等/不等性别、血型众数
定序 (Ordinal)+ 大小比较满意度、排名中位数、众数
定距 (Interval)+ 加减温度(°C)、年份均值、方差
定比 (Ratio)+ 乘除身高、体重、收入几何均值

💡 关键区别: 温度 0°C 不是"没有温度", 所以是定距; 身高 0 cm 是"没有身高", 所以是定比。0 是否有"绝对意义"决定了能否算比率。

ML 应用:

  • 树模型 (XGBoost, LightGBM): 不在意尺度, 定序也能用
  • 线性模型 / 神经网络: 严格区分定距 vs 定比 (因为要乘系数)
  • 距离类模型 (KNN, K-means, SVM): 必须标准化, 否则定比变量压制定距变量

3. 抽样误差:不可消除但可量化

任何抽样都有误差, 这不是统计学的缺陷, 而是物理事实。关键是把误差量化出来。

抽样误差的 3 个主要来源:

来源解释控制方法
随机误差抽到不同样本, 结果会波动增加样本量 (误差 ∝ 1/√n)
抽样偏差抽样框本身就不代表总体改进抽样设计 (分层抽样)
测量误差测不准 (仪器/问卷设计)校准工具、培训调查员

🎯 机器学习里的"抽样": 训练集/测试集划分就是抽样。sklearn 的 train_test_split 用随机抽样, StratifiedShuffleSplit 用分层抽样 — 跟我们这章讲的是一回事!

4. 实验设计三原则

Triola 总结了实验设计的 3 个核心原则 (出自 R.A. Fisher):

4.1 随机化 (Randomization)

目的: 让"未知混杂因素"在处理组/对照组间均匀分布。

# 错: 便利抽样
treatment = df[df["age"] > 30]   # 老年人进实验组
control = df[df["age"] <= 30]    # 年轻人进对照组
# 任何年龄相关的差异, 都不是处理效应

# 对: 随机分配
np.random.seed(42)
df["group"] = np.random.choice(["treatment", "control"], size=len(df))
# 平衡了年龄、性别等所有潜在混杂

4.2 区组化 (Blocking)

目的: 对已知的重要变量,先匹配再随机。把"苹果比苹果, 橙子比橙子"。

# 实验: 比较两种降压药
# 已知"年龄"影响血压, 先按年龄段分组
df["age_block"] = pd.cut(df["age"], bins=[0, 40, 60, 100], labels=["young", "mid", "old"])

# 在每个区组内随机分配药物
df["treatment"] = df.groupby("age_block", group_keys=False).apply(
    lambda g: np.random.choice(["drug_A", "drug_B"], size=len(g))
)

4.3 重复 (Replication)

目的: 同一处理下多次实验, 得到误差的估计没有重复就没有统计显著性

# 每个 (年龄区组 × 药物) 组合做 30 个病人
sample_size_per_cell = 30
df_experiment = df.groupby(["age_block", "treatment"]).apply(
    lambda g: g.sample(n=min(len(g), sample_size_per_cell), random_state=42)
).reset_index(drop=True)

5. 抽样框与覆盖率偏差

抽样框 (Sampling Frame) = 你能"接触到"的名单。理想情况 = 总体, 实际总有差异。

偏差类型例子后果
覆盖率过低1936 文学摘要用电话簿调查总统大选大萧条时期穷人家没电话, 全被遗漏
覆盖率偏高微信调查消费者偏好没微信的老年人/小孩被低估
志愿者偏差网上问卷自愿参与者 ≠ 真实用户

⚠️ 机器学习中的偏差: 训练数据 = 抽样框, 如果它不代表真实世界, 模型上线必失败。这就是为什么 NLP 模型对"非主流方言"表现差, 推荐系统对"长尾用户"不友好。

6. Python 实战: 数据类型自动识别 + 抽样偏差检测

import pandas as pd
import numpy as np

# 模拟一个真实的用户数据集
np.random.seed(42)
n = 5000
df = pd.DataFrame({
    "user_id": range(n),
    "age": np.random.normal(35, 12, n).clip(18, 80).astype(int),
    "income": np.random.lognormal(10.5, 0.5, n),         # 收入对数正态
    "platform": np.random.choice(["iOS", "Android", "Web"], n, p=[0.4, 0.5, 0.1]),
    "satisfaction": np.random.choice([1, 2, 3, 4, 5], n, p=[0.05, 0.1, 0.3, 0.4, 0.15]),
})

# === 自动识别每列的数据类型和测量尺度 ===
def classify_column(s: pd.Series) -> str:
    if s.dtype in ["int64", "float64"]:
        nunique = s.nunique()
        if nunique <= 20:
            return "quantitative-discrete"
        return "quantitative-continuous"
    # 分类
    if s.dtype.name == "category" and hasattr(s.cat, "ordered") and s.cat.ordered:
        return "qualitative-ordinal"
    return "qualitative-nominal"

for col in df.columns:
    kind = classify_column(df[col])
    print(f"  {col:15s}  →  {kind}")

# === 抽样偏差检测: 样本 vs 总体的分布差异 ===
# 假设总体年龄段分布 (来自人口普查)
population_age_dist = pd.Series({
    "18-25": 0.15, "26-35": 0.25, "36-45": 0.20,
    "46-55": 0.20, "56+": 0.20
})
# 我们数据里的分布
df["age_group"] = pd.cut(df["age"], bins=[18, 25, 35, 45, 55, 100],
                          labels=["18-25", "26-35", "36-45", "46-55", "56+"])
sample_age_dist = df["age_group"].value_counts(normalize=True).sort_index()

# 卡方检验看是否有显著差异
from scipy.stats import chisquare
stat, p_value = chisquare(f_obs=sample_age_dist.values,
                          f_exp=population_age_dist.values)
print(f"\n年龄段分布 χ² 检验: stat={stat:.2f}, p={p_value:.3f}")
if p_value &lt; 0.05:
    print("⚠️ 样本与总体分布显著不同, 存在抽样偏差!")

7. 小结

你学到了关键点
数据类型 4 象限定量/分类 × 离散/连续, 决定可用方法
测量尺度 4 级定类 < 定序 < 定距 < 定比, 0 的意义是关键
抽样误差的 3 来源随机、偏差、测量 — 都需要量化
实验设计 3 原则随机化、区组化、重复 — Fisher 1935
抽样框永远是"你接触到的 ≠ 真实世界", 任何统计推断都有前提

8. 习题

  1. 下面哪些是"定比"变量? 哪些是"定距"?

    • 温度(°C)
    • 温度(K)
    • 年龄(岁)
    • 考试成绩(0-100)
    • 银行账户余额
  2. 用卡方检验, 判断 df["platform"] 列是否与总体分布 (iOS=40%, Android=50%, Web=10%) 一致。如果不一致, 说明什么问题?

👉 查看参考答案
  1. 答案:

    • 温度(°C) — 定距 (0°C 不是"没有温度")
    • 温度(K) — 定比 (0K 是"绝对零度", 有意义)
    • 年龄(岁) — 定比 (0 岁有意义)
    • 考试成绩(0-100) — 定距 (0 分不是"不知道成绩", 是真的零分, 但通常按定距处理, 因为不存在"分数比")
    • 银行账户余额 — 定比 (0 元 = 真没余额, 余额可以算比率)
  2. 如果 chisquare p < 0.05, 说明 Web 平台样本比例与总体差异显著 — 可能是 Web 用户更愿意填写问卷, 出现"志愿者偏差"。解决方案: 主动邀请 Web 平台用户填问卷, 或对 Web 平台加权。

9. 下一章


📚 本章来源: 改编自 Triola《基础统计学》第 14 版 第 1 章 1-2、1-3 节, 加入 Python 抽样实战。

章末小测验

检验你对《数据类型与抽样设计》的掌握程度。

1

以下关于数据类型的描述,哪一项是正确的?

2

在机器学习模型中,以下哪种数据处理方法适用于定序数据?

3

关于抽样误差,以下说法正确的是:

4

以下关于测量尺度的描述,哪一项是错误的?

5

在实验设计中,随机化的主要目的是:

讨论区(0)

加载评论中...