程序员的统计思维
本书的定位
- 「本书讨论如何将数据转换为知识。数据是廉价的(至少相对而言如此),但知识却异常宝贵。」
- 三门相互关联的学科
- 概率论:研究随机事件,量化「可能」与「不可能」
- 统计学:根据数据样本推测总情况,大部分统计分析都基于概率
- 计算:量化分析的最佳工具,计算实验有助于理解概率论和统计学中的概念
- 主要目的:让懂编程的人通过编程来理解概率论和统计学
- 很多概念从数学角度很难理解,但用计算方法就比较容易
1.1 第一个孩子出生晚吗
问题的来源
- 「第一胎多在预产期后出生吗?」
- Google 搜索会看到大量讨论:有人说确实如此,有人说没根据,还有人持完全相反的观点
- 常见论据举例
- 「我有两个朋友最近都刚生了第一个孩子,两个宝宝的出生时间都比预产期晚了差不多两周。」
- 「我的第一个孩子晚了两周才出生,我想我的第二个孩子会提前两周。」
- 「我觉得这没道理,因为我姐姐是我妈妈的第一个孩子,她就提前出生了。」
经验之谈(anecdotal evidence)的四个缺陷
- 观察的数量太少
- 第一胎婴儿的妊娠期比较长,但这种差异可能在自然波动范围内
- 需要比较大量孕妇的妊娠期数据才能判断差异是否真的存在
- 选择偏差
- 第一胎婴儿出生比较晚的父母会更有兴趣加入这样的讨论
- 对数据进行选择的过程导致结果不准确
- 确认偏差
- 相信这种说法的人会提供支持示例,怀疑这种说法的人则会引用反例
- 不准确
- 传闻通常都是个人经历,在记忆、表述和复述等方面都不准确
- 观察的数量太少
更好的做法:1.2 统计方法
- 收集数据:使用大型全国性调查的数据
- 描述性统计:计算能总结数据的统计量,评测各种数据可视化的方法
- 探索性数据分析:寻找模式、差异和能解答问题的特征,检查不一致性并确认局限性
- 假设检验:评判观察到的影响是否真实,即是否由随机因素造成
- 估计:用样本数据推断全部人口的特征
1.3 全国家庭成长调查(NSFG)
调查概况
- 美国疾病控制与预防中心(CDC)从 1973 年开始推行 NSFG
- 目的是收集(美国)「家庭的生活、婚姻状况、生育、避孕和男女健康信息」
- 调查对象是 15 到 44 岁的美国人
- 本书使用 Cycle 6 数据,收集于 2002 年 1 月到 2003 年 3 月
横断面研究 vs 纵贯研究
- 横断面研究(cross-sectional study):数据是一群人在某个时间点的情况
- 纵贯研究(longitudinal study):在一段时间内反复观察同一群人
- NSFG 已经进行了 7 次,每次称为一个周期(cycle),但它不是纵贯研究
代表性与过采样
- 通常横断面研究意味着代表性 —— 目标人群中的每个人都有同等的几率参与调查
- 实际上很难实现这种理想状况,但执行调查的人会尽可能做到
- NSFG 不具有代表性,而是有意进行了过采样(oversample)
- 西班牙裔、非裔美国人和青少年的比例都高于他们在美国人口中的比例
- 过采样是为了确保其中被调查者数量够大,从而得到有效的统计推断
- 代价:过采样增大了根据调查结果推断全体人口结论的难度
1.4 表和记录
数据库术语
- 被调查者文件中的每一行表示一个被调查者,这行信息称为一条记录(record)
- 组成记录的变量称为字段(field)
- 若干记录的集合组成一个表(table)
Record有两个子类:Respondent(被调查者)和Pregnancy(怀孕记录)Table有两个子类:Respondents和PregnanciesTable.records是一个 Record 对象的列表GetFields返回字段元组列表,每个元组含四项:field、start、end、转换函数
Pregnancies.GetFields 的字段含义
字段 含义 caseid被调查者的整数 ID prglength怀孕周期,单位是周 outcome怀孕结果的整数代码,代码 1 表示活婴 birthord正常出生的婴儿的顺序,第一胎编号是 1 finalwgt统计权重,该被调查者代表的人群在美国总人口中的比例 字段元组的四个元素
- field:保存该字段属性的名称,用 NSFG 编码手册中的名称,全小写
- start:该字段的起始列编号
- end:结束列编号 —— 跟 Python 中不一样,这里的结束列也是该字段的一部分
- 转换函数:把字符串转换成其他类型;转换失败则属性值为字符串
'NA'
重编码(recode)
- 变量大部分都经过了重编码 —— 原始采集数据经过计算之后得到的值
- 例:第一胎活婴的
prglength,原始数据有wksgest(妊娠周数)时就等于该变量的值,否则用mosgest * 4.33(妊娠月数 × 每月平均周数)估计 - 重编码通常遵循数据一致性和准确性原则
- 除非有特别原因一定要用原始数据,否则应该直接使用重编码后的数据
这本书和《程序员的数学》的区别
同样是「程序员学数学」,两本书的切入点完全不同:
| 《程序员的数学》(结城浩) | 《统计思维》(Downey) | |
|---|---|---|
| 切入 | 具体的数学问题(进位、归纳法、七桥) | 真实数据集(NSFG 调查数据) |
| 工具 | Ruby 验证算法 | Python 分析数据 |
| 目标 | 理解数学概念本身 | 把数据变成知识 |
| 语气 | 「知其所以然」 | 「让懂编程的人通过编程来理解」 |
前者是数学家的写法 —— 先讲定义再推性质;后者是工程师的写法 —— 先有数据和现象再回头解释。
一个数字陷阱
作者自己就演示了汇总统计量有多危险。三个装饰南瓜各 1 磅、两个制饼南瓜各 3 磅、一个巨型南瓜 591 磅:
import math |
输出:
样本: [1, 1, 3, 3, 591] |
均值 119.8 磅,但这里没有「典型」的南瓜 —— 一个 591 磅的巨型南瓜把均值整个拽走了。众数是 3 磅(4 个南瓜),中位数 3 磅。
作者的话:「如果我告诉你『我种的南瓜的平均重量是 100 磅』,那就有问题了,至少这也是一种误导。」
这就是下一章要展开的主线:均值、方差、中位数各自的适用边界,以及为什么要看分布而不是看汇总统计量。