学习分析与语言与人脑
对应:培养方案 专业选修课 · 认知科学模块 · 学期 5 · 共 4 学分
这一篇同时覆盖认知科学模块的两门课,因为它们的学分、学期相同,
而且说到底是同一个问题意识(下面导论⓪会讲透):
课程 学分 学期 一句话 学习分析(Learning Analytics) 2 5 用行为数据推断"学到了什么程度" 语言与人脑 ↗ 2 5 用神经数据推断"语言在哪里、什么时候加工" 标记
↗:《语言与人脑》是与信息科学学院人工智能专业同堂共享课,
同一间教室、同一份作业、同一套考试;《学习分析》是本专业独立开设。前置:这页假设你已经读过
../专业课/教材/笔记-认知神经科学核心.html(下称《认知神经科学核心》)
与../专业课/教材/笔记-语言认知神经科学.html(下称《语言认知神经科学》)。
脑成像测什么(BOLD/HRF/ERP 的物理量)、三个必须破除的误解、N400/P600、失语症、双流模型,
那两页都讲过了,这一页不重复,只引用(写成"见《认知神经科学核心》§6"这种形式)。
如果你还没读那两页,先去读,否则 §6–§8 会缺一大块地基。这份笔记怎么用:所有代码都用
numpy/scipy/pandas写并实际跑过,
复制到终端就能跑。搜索>>> 实跑输出能看到我跑出来的真实结果。
运行环境:~/miniconda3/bin/python,numpy 2.5 / scipy 1.18 / pandas 3.0。
没有用任何机器学习库,因为这一页要讲的正是"这些库在黑箱里替你做了什么",
用 sklearn 一行fit()就什么都看不见了。相关笔记:教育测量与评价的概念请对照
../专业课/教材/笔记-教育评价.html(下称《教育评价》);
随机对照、重复危机、指标争议请对照../专业课/教材/笔记-实验方法论核心.html(下称《实验方法论》);
语言学的结构请对照../专业课/教材/笔记-语言学概论.html(下称《语言学概论》)。
1 导论:这门课在研究什么(先读这个)
1.1 ⓪ 先把"为什么这两门课能合成一篇"说清楚
先看这两门课最表面的样子:一门在教育学院的教室里讲,教材里全是"点击流、作答记录、
预测模型、教学干预";另一门在脑成像中心的机房里讲,教材里全是"fMRI、纤维束、失语症、
语言网络"。它们看起来毫无关系。
但如果把两门课的技术外壳剥掉,剩下的是同一句话:
你永远看不到"心理状态"本身。
你能拿到的只有间接信号。
所有的推断,都是"从信号反推心理状态"。
这个共同的推理结构,就是这一页的主线。具体到两门课:
| 学习分析 | 语言与人脑 | |
|---|---|---|
| 想知道的(看不见的) | 学生"会不会"、"学得怎么样" | 语言加工"在哪里、什么时候、怎么进行" |
| 能拿到的(看得见的) | 点击流、作答对错、答题用时、求助次数 | BOLD 信号、ERP 波形、纤维束走向、损伤后的症状 |
| 中间那一步 | 假设:行为反映学习 | 假设:激活反映加工 |
| 这一步靠什么支撑 | 认知模型(如 BKT 的状态转移) | 实验设计(减法逻辑、对照条件) |
| 失效的方式 | 猜对/失误使行为含噪;预测准 ≠ 教得好 | 相关≠因果;激活不特异;分辨率决定结论 |
左右两列的最后一格,是这一页真正想让你记住的东西,
两门课失效的方式不一样(学习分析死于"标签是含噪的代理变量",神经科学死于"激活是多义的"),
但它们的失效发生在同一个位置上:那个从信号跨到心理状态的箭头。
⭐ 这份笔记真正的"专业课"内容,不是 BKT 的四个参数,也不是弓状束的起止点,
而是让你学会在那根箭头上停下来问一句:这一步凭什么成立?
下面导论 ①–④ 按规格走:先破误解,再定位,再讲能力,最后讲怎么读。
1.2 这两门课不是什么
误解一:"学习分析就是给学校装个数据仪表盘。"
这是最常见的印象,因为它来自产品宣传而不是课堂。真实情况是:
仪表盘(可视化)只是整条链子的最后一环,而前面每一环都可能断。
断点至少有三个:
- 数据不等于构念。"点击了 12 次讨论区"不等于"投入了 12 份努力",
可能只是网页卡了。从原始事件到"这个学生很投入"之间,隔着一次人为的赋值。 - 预测不等于干预。一个模型能算出"这个学生 82% 概率会挂科",
但这句话本身不包含任何能改变这 82% 的动作。而如果干预无效,
这个预测唯一的作用就是把 82% 变成一个自我实现的标签(§5 会展开)。 - 可视化不等于决策。老师看了一张漂亮的雷达图之后做什么,取决于老师,
不取决于图。所以"我们的系统让教师意识到了问题"这种评价,几乎无法证伪。
为什么会误以为"就是仪表盘":因为仪表盘是唯一能演示、能截图、能写进招标书的部分。
整条推理链上最不可靠的那几步,恰恰是最不容易被看见的那几步。
误解二:"语言与人脑 = 把布洛卡区、韦尼克区再讲一遍。"
1836–1874 年那套"两个中心 + 一条弓状束"的模型,在《语言认知神经科学》§4 已经讲过,
这一页一个字都不会重复它。这一页关心的是那套模型为什么必须被换掉,
以及换成了什么。一句话预告:
现代观点里,语言是一组分布式网络,"两个点加一根线"的说法早就站不住;
而且"哪个区管语言"这个问法本身,在分辨率不明确的时候是没有答案的(§8 用可跑代码演示)。
误解三:"有了数据和脑图,就能知道学生在想什么、脑子在算什么。"
这是两门课共享的那个最危险的误会,也是这一页最主要的靶子。它错在两处:
- 学习分析侧:一份 LMS 日志里唯一不存在的东西就是"会不会"。
它对你是隐藏的,你能看到的只是它的含噪投影(答对了,也可能是猜的;答错了,也可能是失误)。
整个知识追踪(§3)就是在给这个"隐藏量"做贝叶斯推断。 - 神经科学侧:看到某区激活,不能推出"被试在做某个心理过程",
这就是《认知神经科学核心》§6 讲的反向推理(reverse inference)。
那一页用贝叶斯算式说明过:一个 80% 特异的指标,阳性时真的为真的概率可能只有三成。
两处错误的数学结构是同一个:漏掉了先验概率、把"多对一"的观测当成"一对一"。
这一个共同点,就是本页最终的落点(§9)。
误解四:"这两门课一个是教育学、一个是脑科学,八竿子打不着。"
见上面的表格。再补一个很实用的对照:
学习分析里的"知识追踪",和神经科学里的"编码模型"(encoding model)是同一个东西的两副面孔。
两者都在做:给定一条观测序列,反推一个看不见的时变状态。
前者用 BKT/HMM 反推"知识状态",后者用 GLM/回归反推"神经响应"。
你在这一页学的贝叶斯更新,在那边换一套符号就能再读一遍。
为什么会有"八竿子打不着"的错觉:因为课程的应用场景差得太远(一间教室 vs 一台核磁),
而方法论内核是同一套。这正好是认知科学这个专业存在的理由,
它把不同应用场景共用的推理结构抽出来单讲。
1.3 它在专业里的位置
认知科学与技术 · 专业选修 · 认知科学模块(4 门 / 8 学分)
│
┌───────────────────────────────┼───────────────────────────────┐
│ │ │
它依赖谁 【本页 · 2 门】 它被谁依赖
──────────── 学习分析 (2 学分 · 学期 5) ──────────────
· 认知神经科学 语言与人脑 ↗ (2 学分 · 学期 5) · 毕业论文(实验/数据)
(BOLD/ERP 怎么读) ──────────────────────── · 智能导学系统 / 自适应
· 语言认知神经科学 共同主线:信号 -> 心理状态的反推 学习产品(§10)
(N400/双流模型)
· 实验方法论 │ · 教育评价 / 大规模测评
(因果、指标、重复) │ (作为对照方法)
· 教育统计学 / 教育评价 │
· 概率统计(贝叶斯) ▼
┌──────────────────────────────────┐
│ 两条平行的反推链 │
└──────────────────────────────────┘
学习分析侧 语言与人脑侧
────────── ──────────
数据:行为日志 数据:脑信号
模型:BKT / 分类器 模型:网络 / 通路
指标:AUC / RMSE 指标:激活 / 分离
风险:标签化 风险:反向推理
│ │
└────── 同一个箭头 ──────┘
§9 在这里合流
和隔壁几门课的分工:
| 课程 | 它负责 | 和本页的分界 |
|---|---|---|
| 认知神经科学核心 | 每种脑成像方法测的是什么物理量;三个误解 | 那页讲怎么读波形与激活;本页讲把它们组织成"网络"和"通路"之后的新问题 |
| 语言认知神经科学 | N400/P600 的具体实验;失语症;双流模型;偏侧化的数字从哪来 | 那页是个案与成分;本页是系统与连接(白质通路、语言网络与一般认知的关系) |
| 实验方法论核心 | 因果推断、重复危机、"指标决定结论" | 那页给判断标准;本页把标准用在两类具体数据上 |
| 教育评价 / 教育统计学 | 测量理论、信度效度、统计推断 | 那两页关心"怎么把能力测准";本页关心"怎么从过程数据里预测",目标不同,指标也不同 |
| 深度学习原理与实践 | 反向传播、注意力、Transformer | 那页讲模型怎么训;本页只把神经网络当"知识追踪的一个更强版本"提一句(§3.6) |
| 大语言模型理论与实践 | 十亿参数规模的生成模型 | 那门关心生成;本页两门课都只关心推断 |
一句话定位:本页是整个选修模块里唯一一门"把方法论本身当主角"的课。
它教的东西不绑定任何具体应用,你今天用来看学习数据,明天用来看脑数据,
后天用来看任何"从间接信号反推隐藏状态"的问题(临床诊断、推荐系统、信用评分,
它们的数学骨架是同一个)。
1.4 真正要教你的能力
具体、可检验,一共五条:
- 能手推 BKT 的一次贝叶斯更新。给你四个参数和一个先验,你能在纸上算出
"答对之后 P(掌握) 变成多少",并说清分子分母各是哪两项(§3.3 手算 + §11 第 3 题)。 - 能说清"可辨识性"(identifiability)是什么意思。给你两组参数和数据,
你能判断"这份数据能不能把它们区分开",并解释为什么预测准和参数对是两回事。
检验方式:读懂 §3.5 那个实验,并自己复现它。 - 能读一份预测模型的报告,并问出三个致命问题。 ①基准率是多少?
②阈值怎么选的?③干预是什么?任何报"我们 AUC = 0.9"的幻灯片,都该被这三问问穿(§4.3)。 - 能画出语言的白质通路图,并说出哪几条的存在性/走向是有争议的。
注意这条能力的重点在后半句,知道"哪里不确定",比背下"哪里确定"更值钱(§6.3)。 - 能识别"信号反推心理状态"这一步的假设。拿到任何一篇论文(教育或神经),
你能指出它的结论依赖哪个没被检验的假设。这是这页最有用的一条,
也是 §9 的全部内容。
1.5 这份笔记的组织逻辑 / 怎么读
组织的原则是:先把共同的逻辑摆出来(§1),再把两条链各自走一遍(§2–§8),
最后回到共同的那个箭头(§9)。
导论 ▸ 破误解 + 定位(你在这)
│
▼
§1 共同的推理结构 ★★ ▸ 定义"信号 -> 心理状态"这个箭头
│ 后面所有内容都挂在它上面
▼
┌── 学习分析侧(§2 - §5)──────────────────────────┐
│ §2 EDM 的任务与数据 ★ ▸ 预测/聚类/关系/序列;一份日志四种问法
│ §3 知识追踪 BKT ★★★ ▸ 四参数 + 贝叶斯更新(手算+代码核对)
│ ▸ 可辨识性实验(本页最关键的实验)
│ §4 评价:AUC/RMSE 与陷阱 ★ ▸ 手算 AUC;基准率;"准 ≠ 有用";学习曲线
│ §5 伦理与隐私 ★ ▸ 这门课的真实议题,不是点缀
└───────────────────────────────────────────────┘
│
▼
┌── 语言与人脑侧(§6 - §8)───────────────────────┐
│ §6 从脑区定位到脑网络 ★★ ▸ Friederici / Hagoort 的框架
│ ▸ 白质通路逐条讲(含"有争议"标注)
│ §7 双语与脑 ★★ ▸ 语言控制;"双语优势"的争议(如实呈现)
│ §8 方法与限制 ★★ ▸ 相关≠因果;语言网络 vs 多需求系统
└───────────────────────────────────────────────┘
│
▼
§9 合流:同一个箭头的两种失效 ★★★ ▸ 全篇落点
│
▼
§10 和你专业的关系(ITS / 自适应学习)-> §11 习题 -> §12 出处索引
阅读顺序建议:
- 第一遍(别停):只读 §1、§3.1–§3.2、§4.3、§6.1、§8.2、§9。
这六处构成本页的主干论证,加起来大约是全篇的三分之一。
跳过所有公式和代码,先把"两门课是同一个问题"这件事吃进去。 - 第二遍(拿纸笔):死磕 §3.3 的手算和 §4.1 的 AUC 手算。
这两处是后面所有讨论的计量单位。算一遍比看十遍有用。 - 第三遍(动手):把 §3.5 的可辨识性代码抄进终端,改一个数。
比如把学生数从 100 改成 20,看"最优参数"漂到哪里去;把练习次数从 8 改成 30,
看可辨识性是不是变好了。这一节的全部价值在于"你亲手看到数据分不开两个世界"。 - 考试前:只看 §11 习题、每节的"边界与批评"、§4.3 那张问题清单、§6.3 的白质通路表。
一页速查:
| 符号 | 读法 | 含义 | 本页在哪 |
|---|---|---|---|
| $P(L_0)$ | 初始掌握率 | 学生一开始就会这道技能的概率 | §3.2 |
| $P(T)$ | 学习率 | 不会 → 会的转移概率 | §3.2 |
| $P(G)$ | 猜对率 | 不会但答对的概率 | §3.2 |
| $P(S)$ | 失误率 | 会但答错的概率 | §3.2 |
| $\mathrm{AUC}$ | 曲线下面积 | 排序质量;随机取一对正负样本、正样本排前面的概率 | §4.1 |
| $\mathrm{RMSE}$ | 均方根误差 | 概率预测的绝对误差 | §4.1 |
| BA 44/45 | 布罗德曼 44/45 区 | 左额下回后部,即"布洛卡区"所在 | §6.2 |
| AF | 弓状束 | 额-颞之间的背侧白质通路 | §6.3 |
| SLF | 上纵束 | 额-顶之间的白质通路(与 AF 关系纠缠) | §6.3 |
| IFOF | 额枕下束 | 腹侧通路;存在性有争议 | §6.3 |
| MD | 多需求系统 | 对"难任务"普遍反应的额顶系统 | §8.2 |
关于数字的一点提醒:本页出现的每一个数字,要么来自我实际跑出来的输出,
要么来自我核对过的文献并标了出处。凡是核对不上的,都写了"出处待查"。
如果哪一处你复现不出来,以你的实际输出为准。
2 全篇的坐标系:那个"信号 → 心理状态"的箭头
这一节只有一件事要做:把两门课公用的那个推理结构,画成一个能反复套用的形状。
后面每一节都会回到这张图。
2.1 你想知道的东西,从来没有直接出现过
把两门课的目标写在一起,你会发现它们是同一个句式的两个填法:
学习分析:
我想知道:他会不会解一元二次方程
我看到的:他在第 7 题选了 B,用了 34 秒,中途点了一次"提示"
语言与人脑:
我想知道:句法加工发生在什么时候
我看到的:他在 400 毫秒后,Cz 电极上有一个负波
这两个句子里,第一行都是心理状态(不可直接观测),第二行都是物理信号(可观测)。
为什么"不可直接观测"这件事必须被反复强调? 因为它是一个反直觉的事实。
你的日常经验告诉你"我知道自己在想什么",那是一种内省的通路,
但内省不是科学观测:它无法被第三方核验,也无法同时用在高通量场景里。
一个老师不可能内省 300 个学生。所以只要你想规模化地知道别人的心理状态,
你就必然要经过一个间接信号。
于是就有了这个箭头:
物理信号 ──────────────► 心理状态
(可观测) 反推 (不可观测)
这一步永远需要一条额外的假设,把两侧连起来。
假设不同,同一个信号会给出不同的心理结论。
记住最后那句话。整页剩下的内容,都是在给这句话提供具体案例。
2.2 连接两侧的"桥",学术上的名字叫模型
一个"模型"在这里的作用非常具体:它是一条编好的、从信号到心理状态的映射规则。
两门课各有一个主力模型:
| 学习分析的桥 | 语言与人脑的桥 | |
|---|---|---|
| 模型 | 知识追踪(BKT / HMM / 神经网络) | 减法逻辑 + 一般线性模型(GLM) |
| 桥的形态 | "答对 ← 由'会'以 $1-P(S)$ 的概率产生" | "激活 ← 由'这个条件比那个条件多出来的加工'产生" |
| 桥的假设 | 不遗忘;每道题只考一个技能;作答之间相互独立 | 纯插入(pure insertion):加一个成分不影响其他成分 |
| 假设破了会怎样 | 参数估计跑偏、P(掌握) 饱和 | 差异被"任务更难"解释掉 |
"纯插入"这个概念值得就地说明,因为它是 fMRI 减法逻辑的命门:
fMRI 实验的经典做法是"任务 A 减去任务 B",把差出来的激活归给 A 比 B 多出的那个成分。
这个减法成立的充要条件是:加上这个成分不会改变其他所有成分的运作方式。
而这个条件几乎从来不成立(加一个成分通常会让整个任务变难、变慢、更要注意)。
《认知神经科学核心》§6 误解一里那条"激活可能来自任务之外的加工",说的就是这件事。
⭐ 两座桥的共同弱点:它们都是"从结果反推原因"。
而"从结果反推原因"的可靠性,取决于原因有多特异(能不能产生别的结果)。
于是两门课的核心难题变成同一个:这个信号特不特异?
2.3 三个层级:谁在反推,谁在被反推
把两门课放在一起看,还有一个结构性的对称很值得注意:
学习分析 语言与人脑
──────── ──────────
第 3 层 教学决策 语言理论
(要不要干预、怎么分班) (语言是不是模块化的)
▲ ▲
│ 反推 │ 反推
第 2 层 知识状态 认知加工过程
(会不会、掌握多少) (句法/语义在何时何地)
▲ ▲
│ 反推 │ 反推
第 1 层 行为记录 神经信号
(对/错、点击、用时) (BOLD、ERP、纤维束)
⭐ 每多往上走一层,就多一个假设,也多一次失效的机会。
这张图解释了本页的两个"重点批评对象"为什么危险:
- §5 的伦理问题(给学生贴"高风险"标签)发生在第 2 层到第 3 层的跨越上:
从"模型算出的概率高"跳到"这个学生需要被特殊对待",这一步没有任何数据能背书。 - §8 的"语言网络与多需求系统重叠"发生在第 2 层内部:
你连"这个激活到底对应哪个加工"都还没确定,就已经在讨论"语言是不是模块"了。
信号 → 心理状态这一步永远依赖假设;
所以任何"数据表明"开头的句子,都该被追问一句"依赖哪条假设"。
3 学习分析(一):教育数据挖掘的任务与数据
从这一节开始走学习分析这条线。先破一个名词:
教育数据挖掘(Educational Data Mining, EDM)和学习分析(Learning Analytics, LA)
是两个高度重叠的社区。粗略地说,EDM 更偏"算法与自动化发现",
LA 更偏"把发现反馈给教学"。本页不区分它们,因为课程本身也不区分。
学习分析最常被引的定义来自 2011 年第一届学习分析与知识国际会议(LAK 2011):
"学习分析是对学习者及其情境的数据进行测量、收集、分析和报告,
目的是理解并优化学习以及学习发生的环境。"
(出处:LAK 2011 会议定义,常与 Siemens & Long 2011 的 EDUCAUSE Review 文章并引)
注意这个定义里的四个动词,测量、收集、分析、报告。
它把"分析"卡在中间:前面依赖数据质量,后面依赖人的使用。
这两头才是学习分析真正的软肋,而中间的算法部分反而是最成熟、最不缺工具的。
3.1 四类任务:同一份日志能问四种问题
EDM 的经典任务是分类(Baker & Yacef 2009 的综述给的框架,后来被多次沿用):
| 任务 | 问的问题 | 典型输出 |
|---|---|---|
| 预测(prediction) | 这个学生接下来会不会做对 / 会不会退课 | 一个概率 |
| 聚类(clustering) | 学生能分成哪几类?(无标签) | 若干组 |
| 关系挖掘(relationship mining) | 什么和什么相关?什么序列反复出现? | 相关系数、关联规则、频繁序列 |
| 用模型来发现(discovery with models) | 拿一个已训好的模型当"测量仪"去研究别的现象 | 科学结论 |
⚠️ 一个容易记错的地方:"行为序列分析"(sequential pattern mining)
在 Baker & Yacef 的框架里属于"关系挖掘"下面的一个子类,不是并列的第五类。
你在别处看到"五大任务"的说法,通常是后来的综述把
"为人类判断做数据蒸馏"(distillation of data for human judgment)补成了第五类,
这个增补是后续工作,不是 2009 那篇原文的分类。
那份 2009 年综述还有一个值得知道的结论:作者对比早期(1995–2005)与 2008–2009 的研究分布,
发现对"预测"的重视在上升,"用模型来发现"在兴起,而"关系挖掘"的比例在下降。
这条趋势对你有直接的现实意义:如果你在 2026 年做学习分析,
默认会被期待去做"预测",哪怕你真正想研究的是"人怎么学"(那是"用模型来发现"的任务)。
任务选择被潮流裹挟,这件事本身就是一个值得警惕的现象。
3.2 实跑:一份 LMS 日志和四种问法
下面这段代码造一份合成日志(不是真实数据,但结构完全按真实 LMS 日志来),
然后用 numpy / pandas 把四类任务各做一遍。
重点是看输出,尤其是看每一个"漂亮数字"后面跟着的那个警告。
import numpy as np
import pandas as pd
rng = np.random.default_rng(2)
# ============ ① 造一份"LMS 日志":学习分析真正的原料 ============
N_STU, N_ITEM = 60, 12
rows = []
for sid in range(1, N_STU + 1):
ability = rng.normal(0, 1) # 隐藏的"水平"——我们永远看不到它
t = 0.0
for iid in range(1, N_ITEM + 1):
t += rng.exponential(40) # 与上一题的间隔(秒)
correct = int(rng.random() < 1 / (1 + np.exp(-(ability - 0.4 * iid / N_ITEM))))
t += rng.exponential(50) if not correct else 0.0 # 答错时明显停顿更久
rows.append(dict(student=sid, item=iid, correct=correct, t_sec=round(t, 1),
n_hint=int(rng.random() < (0.10 + 0.25 * (1 - correct))),
n_play=int(rng.poisson(0.6))))
if rng.random() < 0.08: # 中途退出——真实日志里很常见
break
log = pd.DataFrame(rows)
print("=" * 76)
print("① 一份 LMS 日志(前 8 行)")
print("=" * 76)
print(log.head(8).to_string(index=False))
print("... 共 %d 行(每次'答题'一行)" % len(log))
# ============ ② EDM 的四大任务,同一份日志问四种问题 ============
print()
print("=" * 76)
print("② EDM 的四大任务,同一份日志问四种问题")
print("=" * 76)
# --- 任务 1:预测 ---
log["前半"] = log["item"] <= N_ITEM // 2
g = log.groupby(["student", "前半"]).agg(
acc=("correct", "mean"), speed=("t_sec", "mean"), hints=("n_hint", "mean")).unstack()
g.columns = ["_".join([a, "前" if b else "后"]) for a, b in g.columns]
g = g.dropna()
y = (g["acc_后"] > 0.5).astype(int)
pred = (g["acc_前"] > 0.5).astype(int)
base = max(y.mean(), 1 - y.mean())
print(" [预测] 用'前半段正确率>50%'预测'后半段正确率>50%':")
print(" 准确率 %.3f | 无脑猜多数类的基准线 %.3f | 真正多赚的只有 %.3f"
% ((pred == y).mean(), base, (pred == y).mean() - base))
print(" ⚠️ 这类提升常常比它看起来小得多——先减掉基准线再谈。")
# --- 任务 2:聚类(手写 1 维 k-means)---
x = g["hints_后"].to_numpy() # 聚类特征:后半段平均用提示次数
cent = np.percentile(x, [10, 90]) # 初始化两个中心(用分位数,别用极值)
for _ in range(50):
lab = np.argmin(np.abs(x[:, None] - cent[None, :]), axis=1)
new = np.array([x[lab == k].mean() if (lab == k).any() else cent[k] for k in (0, 1)])
if np.allclose(new, cent): break
cent = new
print()
print(" [聚类] 按'后半段平均用提示次数'做 1 维 k-means(numpy 手写,10 行):")
order = np.argsort(cent)
for rank, k in enumerate(order):
m = lab == k
print(" 第 %d 簇:%2d 人,平均用提示 %.2f 次/题,后半段答对率高于 50%% 的占 %.0f%%"
% (rank + 1, m.sum(), x[m].mean(), 100 * y[m].mean()))
print(" ⚠️ 簇是算法造出来的,不是世界里本来就有的分类——")
print(" 换一个初始化或换一个特征,人数就会变。")
# --- 任务 3:关系挖掘 ---
r = float(np.corrcoef(g["speed_后"], y)[0, 1])
print()
print(" [关系挖掘] '后半段平均每题用时'与'后半段是否答对过半'的相关 r = %+.3f" % r)
print(" ⚠️ 相关不是因果:可能是'水平高所以又快又准',")
print(" 也可能是'题简单所以又快又准'。日志里分不出是哪个。")
print(" 而且这里 y 是二值的,r 会被'削'——真正该用点二列相关或直接报告两组均值。")
# --- 任务 4:行为序列分析 ---
busiest = log.groupby("student").size().idxmax()
seq = log[log.student == busiest]["n_hint"].tolist()
print()
print(" [序列分析] 学生 %d 的提示使用序列(按作答顺序,共 %d 题):" % (busiest, len(seq)))
print(" " + "".join(str(v) for v in seq))
print(" 序列模式('错后必看提示'、'连续两次要提示')是顺序信息的地盘,")
print(" 而这些信息在'汇总成一个平均分'的时候会被扔掉。")
print()
print("=" * 76)
print("③ 这四类任务共享同一个盲点")
print("=" * 76)
print(" 日志里唯一不存在的东西是:学生脑子里到底会不会。")
print(" correct 只是它的一个含噪投影——按 §3 的参数,答对里约 9% 是猜的,")
print(" 答错里约 22% 是其实会的。四类任务没有一类能绕开这一步跨越。")
实跑输出
============================================================================
① 一份 LMS 日志(前 8 行)
============================================================================
student item correct t_sec n_hint n_play
1 1 0 44.1 0 1
2 1 0 40.8 0 1
2 2 0 110.7 1 0
2 3 0 223.6 0 0
2 4 1 245.8 0 2
2 5 1 274.6 0 1
2 6 0 385.5 0 0
2 7 1 395.5 1 1
... 共 466 行(每次'答题'一行)
============================================================================
② EDM 的四大任务,同一份日志问四种问题
============================================================================
[预测] 用'前半段正确率>50%'预测'后半段正确率>50%':
准确率 0.676 | 无脑猜多数类的基准线 0.647 | 真正多赚的只有 0.029
⚠️ 这类提升常常比它看起来小得多——先减掉基准线再谈。
[聚类] 按'后半段平均用提示次数'做 1 维 k-means(numpy 手写,10 行):
第 1 簇:16 人,平均用提示 0.07 次/题,后半段答对率高于 50% 的占 62%
第 2 簇:18 人,平均用提示 0.44 次/题,后半段答对率高于 50% 的占 11%
⚠️ 簇是算法造出来的,不是世界里本来就有的分类——
换一个初始化或换一个特征,人数就会变。
[关系挖掘] '后半段平均每题用时'与'后半段是否答对过半'的相关 r = -0.442
⚠️ 相关不是因果:可能是'水平高所以又快又准',
也可能是'题简单所以又快又准'。日志里分不出是哪个。
而且这里 y 是二值的,r 会被'削'——真正该用点二列相关或直接报告两组均值。
[序列分析] 学生 5 的提示使用序列(按作答顺序,共 12 题):
000010001010
序列模式('错后必看提示'、'连续两次要提示')是顺序信息的地盘,
而这些信息在'汇总成一个平均分'的时候会被扔掉。
============================================================================
③ 这四类任务共享同一个盲点
============================================================================
日志里唯一不存在的东西是:学生脑子里到底会不会。
correct 只是它的一个含噪投影——按 §3 的参数,答对里约 9% 是猜的,
答错里约 22% 是其实会的。四类任务没有一类能绕开这一步跨越。
这张输出里最该盯住的三个数字:
- 预测的 0.676 和基准线 0.647。一个"0.676 准确率"的模型听上去还行,
但它只比"无脑猜多数类"多赚了 0.029。这是学习分析论文里最常见的数字包装手法:
只报准确率、不报基准线。你以后看到任何准确率,第一个动作就是问基准线。 - 聚类那两簇的答对率 62% vs 11%。这个差距看起来很大、很有说服力,
但请注意:这两簇是"按提示使用率"分出来的,而提示使用率是我用来分组的变量。
所谓"发现两类学生",一部分是把输入变量换了个说法重复了一遍。
这类"同义反复式的发现"在无监督学习里极其常见。 - 相关 r = −0.442。这个数字是真的、可复现的(数据生成时我确实让答错更慢)。
但它是被我"造"出来的,这就是模拟数据的危险:它能演示方法,但不能证明结论。
⚠️ 这一段代码的性质必须说清楚:它是教学演示,数据是我合成的,
所以里面的任何"发现"都只说明方法能跑通,不说明任何关于真实学生的事实。
真实数据上的数字才会有真实含义,而真实数据你拿不到(要过伦理审查、要签数据协议,见 §5)。
3.3 典型数据:从点击流到面部
学习分析能拿到的数据,按"离心理状态的距离"排一下序,会看得更清楚:
离行为近 ─────────────────────────────────────────► 离心理状态近
│ │ │ │
日志事件 作答记录 用时/修改 眼动/面部
(点开、播放、 (对/错、选了 (每题耗时、 (注视时长、
提交、关闭) 哪个选项) 改了几次) 瞳孔、表情)
│ │ │ │
量最大、最容易拿 最常被当作 推断"犹豫/ 信息最丰富、
但也最模糊 "学习"的直接证据 流利/放弃" 也最贵、最少见
逐层说清楚每一层的坑:
- 日志事件(点击流):量最大,但它是"界面行为的投影",不是"心理活动的投影"。
同一句"点击了讨论区",在手机端、在网页端、在断网重连时,含义完全不同。
这类数据的头号问题跟噪声无关,真正要命的是"测的不是你想测的东西"(构念效度问题)。 - 作答记录:看似最干净(对就是对),但它同时是最容易被过度信任的一类。
§3 整节都在处理它的含噪性:对错只告诉你一个二值结果,不告诉你过程。 - 用时 / 修改次数:这是过程信息,比结果信息更接近心理状态。
但它对界面、设备、网络延迟极度敏感。做跨学校、跨设备比较时,这个变量基本不可用。 - 眼动 / 面部:信息最丰富(能看注意力分配、认知负荷、情绪)。
代价是需要专门设备、需要额外的伦理程序、样本量上不去。
《学习分析》这门课如果讲到这部分,重点一定是"这些信号也不是心理状态本身",
瞳孔放大可以是认知负荷,也可以是光线变化、是情绪唤起、是咖啡因。
⚠️ 一个真实的行业教训:面部识别式"注意力检测"在教育产品里被大量宣传,
但它的效度证据非常薄弱,而且它引入的伦理风险远大于它带来的教学价值(§5.3 会展开)。
遇到这类产品,你的默认立场应该是怀疑,而不是惊叹。
3.4 边界与批评
| 问题 | 说明 |
|---|---|
| 构念效度 | 日志事件测的是"界面操作",不是"学习"。这一步的跳跃常常被默认成立而不被检验 |
| 平台依赖 | 换一套 LMS,同一批学生的"行为特征"就变了。跨系统、跨版本的可比性极差 |
| 缺失值有含义 | 退出、跳过、不点,本身就是信息,但常规的缺失值处理会把它们抹掉 |
| 日志里的学生知道自己在被记录 | 这会不会改变行为?(有点像霍桑效应)很少有人在教育场景里认真检验过 |
| 基准线的缺席 | 绝大多数"我们的模型准确率 X%"的报告不报基准线(见 §4.3) |
学习分析的数据不是"关于学习的证据",
它是"关于界面操作"的证据。把它当成前者,是这门课最常见的错误。
4 学习分析(二):知识追踪(全篇最硬的一节)
这一节回答学习分析的核心问题:
怎么从一串"对/错"里,推断出一个看不见的、随时间变化的"会不会"?
为什么这是核心问题? 因为 §2 的四类任务,最后几乎都要落到它上面:
预测需要它("他接下来会不会做对"直接就是知识状态的函数),
聚类可以用它(按"掌握轨迹"而不是按"平均分"分学生),
关系挖掘经常用它当因变量,自适应学习(§10)更是完全靠它决定下一题出什么。
4.1 问题的困难在哪:对错是"含噪投影"
先看几个真实学生会长什么样(下面是概念示意):
学生甲 1 1 1 1 1 1 全对——他是真会,还是这六题太简单?
学生乙 0 0 0 0 0 0 全错——他是真不会,还是根本没在看题?
学生丙 0 0 0 1 1 1 先错后对——他在第 4 题学会了,还是前三题在乱猜?
学生丁 1 0 1 1 0 1 忽对忽错——是不会但蒙对了几次,还是会了但失误了几次?
四种轨迹,"会不会"的真相可以是完全不同的。具体地说,有两个机制让"对错"不能直接读成"会不会":
- 猜(guess):不会,但答对了。
- 失误(slip):会,但答错了。
所以"会不会"必须被当成一个隐变量(latent variable),
用概率模型从观测序列里反推它。这就是知识追踪(Knowledge Tracing, KT)。
先看一眼这两个机制到底有多严重。下面这段代码模拟 20000 个"真值已知"的学生,
然后统计"猜对"和"失误"在观测里各占多大比例,
这两个比例,是整节所有讨论的出发点。
import numpy as np
rng = np.random.default_rng(0)
# ============ BKT 前向模拟:一个"真值已知"的学生 ============
P_L0, P_T, P_G, P_S = 0.30, 0.10, 0.20, 0.10 # 示意取值,非原论文数值
def simulate(n_steps, rng, p_l0=P_L0, p_t=P_T, p_g=P_G, p_s=P_S):
"""返回 (隐状态序列, 作答序列)"""
know = rng.random() < p_l0
states, obs = [], []
for _ in range(n_steps):
states.append(know)
# 观测:知道则可能"失误",不知道则可能"猜对"
p_correct = (1 - p_s) if know else p_g
obs.append(rng.random() < p_correct)
# 学习机会:不知道的学生以 P(T) 学会
if not know:
know = rng.random() < p_t
return states, obs
print("参数:P(L0)=%.2f P(T)=%.2f P(G)=%.2f P(S)=%.2f" % (P_L0, P_T, P_G, P_S))
print()
print("三个学生的模拟(√=会,×=不会;1=答对,0=答错)")
print(" 步 " + "".join("%4d" % i for i in range(1, 21)))
for s in range(3):
st, ob = simulate(20, rng)
print(" S%d 状态 " % (s+1) + "".join("%4s" % ("√" if k else "×") for k in st)
+ " 真值掌握=%s" % ("是" if st[-1] else "否"))
print(" S%d 作答 " % (s+1) + "".join("%4d" % int(o) for o in ob))
print()
# ---- 统计:猜对/失误到底有多常见 ----
NS = 20000
tot_slip = tot_guess = n_know = n_notknow = 0
for _ in range(NS):
st, ob = simulate(20, rng)
for k, o in zip(st, ob):
if k:
n_know += 1; tot_slip += (0 if o else 1)
else:
n_notknow += 1; tot_guess += (1 if o else 0)
print("—— 20000 个学生 × 20 步 的混淆统计 ——")
print(" 真·不会的作答共 %7d 次,其中猜对 %6d 次 → 猜对率 %.3f(=P(G)=%.2f)"
% (n_notknow, tot_guess, tot_guess/n_notknow, P_G))
print(" 真·会的 作答共 %7d 次,其中失误 %6d 次 → 失误率 %.3f(=P(S)=%.2f)"
% (n_know, tot_slip, tot_slip/n_know, P_S))
print()
print(" 答对 ≠ 会:答对里有 %.1f%% 是猜的;答错 ≠ 不会:答错里有 %.1f%% 其实是会的。"
% (100*tot_guess/(tot_guess + (n_know-tot_slip)),
100*tot_slip/(tot_slip + (n_notknow-tot_guess))))
实跑输出
参数:P(L0)=0.30 P(T)=0.10 P(G)=0.20 P(S)=0.10
三个学生的模拟(√=会,×=不会;1=答对,0=答错)
步 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
S1 状态 × √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ 真值掌握=是
S1 作答 0 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1
S2 状态 × × × × × × × × × × × × × √ √ √ √ √ √ √ 真值掌握=是
S2 作答 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1
S3 状态 × × × √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ 真值掌握=是
S3 作答 0 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 1 0 0 1
—— 20000 个学生 × 20 步 的混淆统计 ——
真·不会的作答共 124356 次,其中猜对 24852 次 → 猜对率 0.200(=P(G)=0.20)
真·会的 作答共 275644 次,其中失误 27683 次 → 失误率 0.100(=P(S)=0.10)
答对 ≠ 会:答对里有 9.1% 是猜的;答错 ≠ 不会:答错里有 21.8% 其实是会的。
这张输出要读三个地方:
- 看看 S1 的作答行(
0 1 1 0 1 1 1 0 ...):他第 2 步就学会了,此后一直会,
但作答里有 3 个 0。这三个 0 全是失误,而你在日志里看到的只是"答错了"。 - 看看 S2:他前 13 步真的不会,一直答错,直到第 14 步学会。
这是一个"会不会"真的发生跳变的学生,而日志里只有一串 0 后面跟着一串 1。
知识追踪要做的,就是从这串数字里定位那个"第 14 步"。 - 最下面那两行是本节的核心数字:
答对里 9.1% 是猜的;答错里 21.8% 是其实会的。
也就是说,你拿到的标签,有五分之一左右是"错的"(至少,与你要测的那个隐变量不符)。
这两个数字会在后面每一节里再出现。
⭐ 注意这一步的性质:它和 §1 的箭头是同一个东西。
"会不会"是心理状态,"对错"是物理信号。知识追踪就是那根箭头的一个具体实现。
4.2 BKT 的四个参数
贝叶斯知识追踪(Bayesian Knowledge Tracing, BKT)由 Corbett 和 Anderson 在 1995 年提出
(Corbett, A. T., & Anderson, J. R. (1995). Knowledge tracing: Modeling the acquisition of
procedural knowledge. User Modeling and User-Adapted Interaction, 4(4), 253–278)。
它的想法极其简单:把"会不会"当成一个二值隐状态(会 / 不会),
学生每做一道题,这个状态要么不变、要么从不变成会。整个模型只有四个参数:
| 参数 | 名字 | 含义 | 直觉 |
|---|---|---|---|
| $P(L_0)$ | 初始掌握率 | 一上来就会的概率 | "这题他以前学过没有" |
| $P(T)$ | 学习率 | 不会 → 会的转移概率 | 每次练习机会有多"值钱" |
| $P(G)$ | 猜对率 | 不会但答对的概率 | 选择题四选一 = 0.25 |
| $P(S)$ | 失误率 | 会但答错的概率 | 手滑、看错、算错 |
外加一条最关键的假设:没有遗忘。一旦 $L$ 从"不会"翻到"会",就永远停在"会"。
换句话说 $P(\text{遗忘}) = 0$,是被硬编码进去的。
为什么敢这么假设? 因为在一个知识点内部的连续几道练习题这个尺度上,
遗忘的效应确实很小。但这条假设正是 BKT 后来被批评最多的地方(§3.6 会把代价算给你看)。
这四个参数的来历值得说一句:BKT 是 ACT-R 理论(Anderson 1993)的一个"四参数简化",
而它的贝叶斯形式可以追溯到 Atkinson (1972);
后来 Reye (2004) 证明了它等价于一个隐马尔可夫模型 / 动态贝叶斯网络。
换句话说:BKT 不是从数据里"学"出来的架构,它是从一个认知理论里"推"出来的架构。
这一点很重要,它意味着 BKT 的参数有心理学解释,
但也意味着它的结构受限于那个理论(比如"不遗忘"就是理论假设,不是数据结论)。
4.3 更新公式:逐项推导
现在把公式写出来,每一项都解释为什么会出现。
第一步:预测这道题答对的概率。
$$P(C_t) = P(L_t)\,(1 - P(S)) + (1 - P(L_t))\,P(G)$$
逐项读:
- 这道题答对,只有两条互斥的路:"会了"且没失误,或者 "不会"但猜对了。
- 第一项 $P(L_t)(1-P(S))$:会的概率 × 会了却不失误的概率。
- 第二项 $(1-P(L_t))P(G)$:不会的概率 × 猜对的概率。
- 两项相加就是全概率公式,没有任何花招。
第二步:看到作答结果,更新信念(贝叶斯公式)。
答对时:
$$P(L_t \mid \text{答对}) = \frac{P(L_t)\,(1-P(S))}{P(C_t)}$$
答错时:
$$P(L_t \mid \text{答错}) = \frac{P(L_t)\,P(S)}{1-P(C_t)}$$
逐项读:
- 分子 = 先验 × 似然:$P(L_t)$ 是"作答之前你认为他会";$(1-P(S))$ 是"如果他会,
产生'答对'这个观测的概率"。 - 分母 = 这个观测出现的总概率(归一化常数)。答对的分母就是 $P(C_t)$;
答错的分母是 $1-P(C_t)$(因为观测只有对/错两种,概率加起来必须是 1)。 - 分母的作用是"重新分配概率":把"这个观测本身有多常见"除掉,
剩下的才是"这个观测给'他会'增加了多少证据"。 - 注意分子里只有 $P(S)$ 或 $P(G)$ 中的一个:答对的证据只和"失误率"有关,
答错的证据只和"猜对率"有关。这是因为在"会"和"不会"两种假设下,
产生这个观测的路径各只有一条。
第三步:学习机会(把状态推进到下一题)。
$$P(L_{t+1}) = P(L_t \mid \text{观测}) + \bigl[1 - P(L_t \mid \text{观测})\bigr]\,P(T)$$
逐项读:
- 下一题之前"会"的概率 = 本来就会的 + 本来不会、但在这道题上学会的。
- 第二项里那个 $[1 - P(L_t \mid \text{观测})]$ 就是"原本不会的概率",
乘上 $P(T)$ 就是"在这道题上学会的概率"。 - 为什么这一步放在观测之后、而不是之前? 这是一个建模选择,
含义是"先根据作答更新信念,再让学生经历一次学习机会"。
两种顺序在文献里都出现过,本页沿用 Corbett & Anderson 的原始顺序。 - 注意答错时 $P(L)$ 也可能上升(如果 $P(T)$ 够大),
这是很多人第一次看 BKT 会卡住的地方,下面手算里会亲眼看到。
下面把这三步真的算一遍。
import numpy as np
P_L0, P_T, P_G, P_S = 0.30, 0.10, 0.20, 0.10
def bkt_update(p_know, correct, p_t=P_T, p_g=P_G, p_s=P_S):
"""输入:做完这道题之前认为他会的概率;输出:(作答后的信念, 下题前的信念)"""
if correct:
post = p_know * (1 - p_s) / (p_know * (1 - p_s) + (1 - p_know) * p_g)
else:
post = p_know * p_s / (p_know * p_s + (1 - p_know) * (1 - p_g))
p_next = post + (1 - post) * p_t
return post, p_next
print("=" * 74)
print("第一步:手算一次更新(对着公式看)")
print("=" * 74)
p = P_L0
print("先验 P(L) = %.4f" % p)
print()
print("情形 A:答对了")
num = p * (1 - P_S); den = p * (1 - P_S) + (1 - p) * P_G
print(" 分子 P(L)·(1-P(S)) = %.4f × %.2f = %.4f" % (p, 1-P_S, num))
print(" 分母 分子 + (1-P(L))·P(G) = %.4f + %.4f × %.2f = %.4f" % (num, 1-p, P_G, den))
print(" 后验 P(L|答对) = %.4f / %.4f = %.4f" % (num, den, num/den))
print(" 再算 P(L) ← 后验 + (1-后验)·P(T) = %.4f" % (num/den + (1-num/den)*P_T))
post_c, next_c = bkt_update(p, True)
print(" 代码核对:后验=%.4f 下一题前=%.4f ✓" % (post_c, next_c))
print()
print("情形 B:答错了(同样的先验)")
num2 = p * P_S; den2 = p * P_S + (1 - p) * (1 - P_G)
print(" 分子 P(L)·P(S) = %.4f × %.2f = %.4f" % (p, P_S, num2))
print(" 分母 分子 + (1-P(L))·(1-P(G)) = %.4f + %.4f × %.2f = %.4f" % (num2, 1-p, 1-P_G, den2))
print(" 后验 P(L|答错) = %.4f / %.4f = %.4f" % (num2, den2, num2/den2))
print(" 再算 P(L) ← 后验 + (1-后验)·P(T) = %.4f" % (num2/den2 + (1-num2/den2)*P_T))
post_w, next_w = bkt_update(p, False)
print(" 代码核对:后验=%.4f 下一题前=%.4f ✓" % (post_w, next_w))
print()
print("⚠️ 注意 B 的两段式:答错把 P(L) 从 %.2f 打到 %.4f(后验),"
% (P_L0, post_w))
print(" 紧接着'学习机会'又把它抬回 %.4f——因为'不会'的学生还有 %.0f%% 的概率在这一步学会。"
% (next_w, P_T*100))
print(" 所以一次答错并不会把'他不会'钉死;反过来,一次答对也不等于'他会了'。")
print()
print("=" * 74)
print("第二步:一条真实作答序列上的信念追踪")
print("=" * 74)
obs = [0,1,1,0,1,1,1,0,1,1,1,1,1,1,1] # 上面 S1 的前 15 步
print(" 步 作答 作答前P(L) 后验P(L) 下题前P(L)")
p = P_L0
for i, o in enumerate(obs, 1):
post, p_next = bkt_update(p, bool(o))
print(" %2d %s %.4f %.4f %.4f" % (i, "对" if o else "错", p, post, p_next))
p = p_next
print()
print("末尾 P(L) = %.4f(真值是:他在第 2 步学会了,此后一直会)" % p)
print()
print("⚠️ 看步 13-15:P(L) 显示为 1.0000 就不再变化(其实是浮点精度,不是真等于 1)。")
print(" 把这个'已经确信他会了'的信念拿去做一次压力测试——连续答错:")
q = 0.9999
print(" 连错 0 次:P(L) = %.6f" % q)
for i in range(1, 6):
_, q = bkt_update(q, False)
print(" 连错 %d 次:P(L) = %.6f" % (i, q))
print(" ⭐ 前 3 次连错,信念只从 0.9999 松到 0.9642;要到第 4、5 次才真正塌下来。")
print(" 这个'惯性'来自'不会遗忘'这条假设:每一步答错都被优先解释成'失误'。")
print(" 真实的学生是会忘的——这是 BKT 最常被批评的一条。")
实跑输出
==========================================================================
第一步:手算一次更新(对着公式看)
==========================================================================
先验 P(L) = 0.3000
情形 A:答对了
分子 P(L)·(1-P(S)) = 0.3000 × 0.90 = 0.2700
分母 分子 + (1-P(L))·P(G) = 0.2700 + 0.7000 × 0.20 = 0.4100
后验 P(L|答对) = 0.2700 / 0.4100 = 0.6585
再算 P(L) ← 后验 + (1-后验)·P(T) = 0.6927
代码核对:后验=0.6585 下一题前=0.6927 ✓
情形 B:答错了(同样的先验)
分子 P(L)·P(S) = 0.3000 × 0.10 = 0.0300
分母 分子 + (1-P(L))·(1-P(G)) = 0.0300 + 0.7000 × 0.80 = 0.5900
后验 P(L|答错) = 0.0300 / 0.5900 = 0.0508
再算 P(L) ← 后验 + (1-后验)·P(T) = 0.1458
代码核对:后验=0.0508 下一题前=0.1458 ✓
⚠️ 注意 B 的两段式:答错把 P(L) 从 0.30 打到 0.0508(后验),
紧接着'学习机会'又把它抬回 0.1458——因为'不会'的学生还有 10% 的概率在这一步学会。
所以一次答错并不会把'他不会'钉死;反过来,一次答对也不等于'他会了'。
==========================================================================
第二步:一条真实作答序列上的信念追踪
==========================================================================
步 作答 作答前P(L) 后验P(L) 下题前P(L)
1 错 0.3000 0.0508 0.1458
2 对 0.1458 0.4343 0.4909
3 对 0.4909 0.8127 0.8314
4 错 0.8314 0.3814 0.4433
5 对 0.4433 0.7818 0.8036
6 对 0.8036 0.9485 0.9536
7 对 0.9536 0.9893 0.9904
8 错 0.9904 0.9279 0.9351
9 对 0.9351 0.9848 0.9863
10 对 0.9863 0.9969 0.9972
11 对 0.9972 0.9994 0.9994
12 对 0.9994 0.9999 0.9999
13 对 0.9999 1.0000 1.0000
14 对 1.0000 1.0000 1.0000
15 对 1.0000 1.0000 1.0000
末尾 P(L) = 1.0000(真值是:他在第 2 步学会了,此后一直会)
⚠️ 看步 13-15:P(L) 显示为 1.0000 就不再变化(其实是浮点精度,不是真等于 1)。
把这个'已经确信他会了'的信念拿去做一次压力测试——连续答错:
连错 0 次:P(L) = 0.999900
连错 1 次:P(L) = 0.999281
连错 2 次:P(L) = 0.994846
连错 3 次:P(L) = 0.964181
连错 4 次:P(L) = 0.793802
连错 5 次:P(L) = 0.392390
⭐ 前 3 次连错,信念只从 0.9999 松到 0.9642;要到第 4、5 次才真正塌下来。
这个'惯性'来自'不会遗忘'这条假设:每一步答错都被优先解释成'失误'。
真实的学生是会忘的——这是 BKT 最常被批评的一条。
三个必须停下来看的地方:
- 步 1 答错之后,P(L) 从 0.30 掉到 0.0508,但下一题之前又回到 0.1458。
这就是"学习机会"项在起作用。它的实际后果是:BKT 对"答错"的惩罚是有下限的。
一个总是答错的学生,P(L) 会稳定在某个正值上而不是 0,
因为模型永远给"他可能刚好在这一步学会了"留了空间(这个正值可以解析算出来,见 §11 第 4 题)。 - 步 3 就冲到 0.83,步 7 就接近 0.99。 BKT 的信念收敛得非常快,
这在数据稀疏时是优点、在数据噪声大时是缺点:
三次连续答对之后,模型已经相当确信"他会了",而真实情况可能只是三次猜对。 - "不遗忘"的代价在压力测试里暴露无遗:连错三次只把它从 0.9999 拉到 0.9642。
换成真实学生,你早就该怀疑"他是不是忘了/这个技能他其实没真会",
但模型还在解释成"失误"。后面 §3.6 会讲这个问题的最直接修法。
4.4 数学核对:那个递归公式真的是"后验"吗?
上面的更新公式是从贝叶斯定理"推"出来的。既然是推导,就该能被独立验证。
下面做一个硬的核对:把一条 6 步序列的所有可能隐状态轨迹($2^6 = 64$ 条)
全部枚举出来,用定义直接求和,算出精确的后验,再和递归公式的结果逐位比对。
import numpy as np
import itertools
P_L0, P_T, P_G, P_S = 0.30, 0.10, 0.20, 0.10
obs = [0, 1, 1, 0, 1, 1]
T = len(obs)
def p_traj(states, obs):
"""P(隐状态轨迹, 观测) —— 逐项写出,不用任何技巧"""
p = P_L0 if states[0] else (1 - P_L0)
for t in range(1, len(states)):
prev, cur = states[t-1], states[t]
if prev and cur: p *= 1.0 # 会了不会忘
elif (not prev) and cur: p *= P_T # 学会
elif prev and (not cur): p *= 0.0 # 会 -> 不会:模型不含遗忘
else: p *= 1 - P_T # 仍然不会
for t in range(len(states)):
if states[t]: p *= (1 - P_S) if obs[t] else P_S # 会:可能失误
else: p *= P_G if obs[t] else (1 - P_G) # 不会:可能猜对
return p
def exact_filter(t): # P(L_t | o_1..t):只用到现在为止的观测
trajs = list(itertools.product([False, True], repeat=t + 1))
w = {s: p_traj(list(s), obs[:t+1]) for s in trajs}
z = sum(w.values())
return sum(v for s, v in w.items() if s[t]) / z
def exact_smoother(t): # P(L_t | o_1..T):用上全部观测(含"未来")
trajs = list(itertools.product([False, True], repeat=T))
w = {s: p_traj(list(s), obs) for s in trajs}
z = sum(w.values())
return sum(v for s, v in w.items() if s[t]) / z
# ---- BKT 递归(在线,只能看到过去) ----
rec, p = [], P_L0
for o in obs:
pc = p * (1 - P_S) + (1 - p) * P_G
post = (p * (1 - P_S) / pc) if o else (p * P_S / (1 - pc))
rec.append(post); p = post + (1 - post) * P_T
print("=" * 78)
print("核对一:BKT 递归 = 精确的在线滤波 P(L_t | o_1..t) 吗?")
print("=" * 78)
print(" 步 观测 BKT 递归 全枚举(滤波) 差值")
d = []
for t in range(T):
e = exact_filter(t); d.append(abs(rec[t] - e))
print(" %2d %d %.8f %.8f %.1e" % (t+1, obs[t], rec[t], e, abs(rec[t]-e)))
print(" 最大差值 = %.1e → 递归公式给出的确实是精确后验,不是近似。✓" % max(d))
print()
print("=" * 78)
print("核对二:同一个量,如果允许它看未来,答案就不一样了")
print("=" * 78)
print(" 步 观测 在线滤波 P(L_t|o_1..t) 离线平滑 P(L_t|o_1..T) 差值")
for t in range(T):
ef, es = exact_filter(t), exact_smoother(t)
print(" %2d %d %.6f %.6f %+.6f"
% (t+1, obs[t], ef, es, es-ef))
print()
print(" ⭐ 第 1 步的差别最刺眼:在线看是 0.051(几乎确定他不会),")
print(" 知道后面 5 题全对之后再回头看,就变成 0.240。")
print(" 同一份数据、同一个模型、同一个时间点,两个答案。")
print(" 差别只在于:你允许这个推断用多少信息——而这是一条假设。")
实跑输出
==============================================================================
核对一:BKT 递归 = 精确的在线滤波 P(L_t | o_1..t) 吗?
==============================================================================
步 观测 BKT 递归 全枚举(滤波) 差值
1 0 0.05084746 0.05084746 0.0e+00
2 1 0.43434343 0.43434343 5.6e-17
3 1 0.81270903 0.81270903 1.1e-16
4 0 0.38140534 0.38140534 3.3e-16
5 1 0.78179457 0.78179457 2.2e-16
6 1 0.94849127 0.94849127 1.1e-16
最大差值 = 3.3e-16 → 递归公式给出的确实是精确后验,不是近似。✓
==============================================================================
核对二:同一个量,如果允许它看未来,答案就不一样了
==============================================================================
步 观测 在线滤波 P(L_t|o_1..t) 离线平滑 P(L_t|o_1..T) 差值
1 0 0.050847 0.239531 +0.188683
2 1 0.434343 0.686655 +0.252312
3 1 0.812709 0.776080 -0.036629
4 0 0.381405 0.793965 +0.412560
5 1 0.781795 0.922737 +0.140942
6 1 0.948491 0.948491 +0.000000
⭐ 第 1 步的差别最刺眼:在线看是 0.051(几乎确定他不会),
知道后面 5 题全对之后再回头看,就变成 0.240。
同一份数据、同一个模型、同一个时间点,两个答案。
差别只在于:你允许这个推断用多少信息——而这是一条假设。
核对一的结果(最大差值 $3.3\times10^{-16}$)说明递归公式是对的,
那点残差纯粹是浮点误差。这一步很值得做:
它把"我觉得这个公式应该是对的"变成了"我算过,它精确等于定义"。
核对二的结果更有意思,它是一次意外收获。
我原本只想做核对一,但把"用全部观测"和"只用过去"分开写之后,
两个数字立刻暴露出同一个模型的两种推断模式:
| 在线滤波(filtering) | 离线平滑(smoothing) | |
|---|---|---|
| 用到的信息 | 只用到当前时刻为止 | 用到整条序列(包括"未来") |
| 典型场景 | 自适应学习系统必须这样(未来还没发生) | 事后分析、给学生出报告 |
| 第 1 步的答案 | 0.051 | 0.240 |
⭐ 问题落在"你允许推断用多少信息"上,"哪个对"这个问法是走偏的。
而"用多少信息"是一条建模假设,不是数据的一部分。
这句话,就是 §9 那个"反推依赖假设"的第一个具体实例。
顺带一个实用提醒:如果你用平滑的结果去评估一个在线系统,你会高估它,
因为线上系统拿不到未来。这类"离线指标比线上好"的现象,
在推荐系统、知识追踪、教育预警里都是老大难问题。
4.5 ⭐ 参数从哪来:拟合,以及"数据分不开两个世界"的实验
上面的四个参数($P(L_0)=0.3$、$P(T)=0.1$……)是我直接给的。
真实场景里它们必须从数据里估出来。这一节做这件事,
然后展示一个比拟合本身重要得多的发现。
4.5.1 怎么拟合:最大似然
思路很直白:找一组参数,使"观测到这批数据的概率"最大。
对数似然写出来是:
$$\log \mathcal{L}(\theta) = \sum_{\text{学生 } i}\ \sum_{\text{题 } t} \log \Bigl[ \underbrace{P(C_t)\,}_{\text{若答对}} \ \text{或}\ \underbrace{1-P(C_t)}_{\text{若答错}} \Bigr]$$
逐项读:外层求和遍历所有学生(假设学生之间独立),内层遍历这个学生的所有作答;
每一项加的是"模型预测了 $P(C_t)$,而实际观测到对/错,这个观测的对数概率"。
注意 $P(C_t)$ 是按上一节的递归算出来的(因为信念要随着作答不断更新)。
所以这是一个带有隐状态的似然,没有解析解,只能用数值方法搜。
4.5.2 网格搜索:把参数空间扫一遍
四维参数空间不大,直接扫网格最直观(也最不容易被优化器的坑骗)。
import numpy as np
rng = np.random.default_rng(7)
# ================= 生成"考试数据" =================
TRUE = dict(l0=0.30, t=0.10, g=0.20, s=0.10)
N_STU, N_ITEM = 100, 8 # 100 个学生,每个技能只练 8 次(真实 ITS 里很常见)
def simulate(p_l0, p_t, p_g, p_s, n_stu, n_item, rng):
data = np.zeros((n_stu, n_item), dtype=int)
for i in range(n_stu):
know = rng.random() < p_l0
for j in range(n_item):
data[i, j] = rng.random() < ((1 - p_s) if know else p_g)
if not know:
know = rng.random() < p_t
return data
data = simulate(TRUE['l0'], TRUE['t'], TRUE['g'], TRUE['s'], N_STU, N_ITEM, rng)
print("模拟数据:%d 个学生 × %d 道题,总正确率 %.3f" % (N_STU, N_ITEM, data.mean()))
print("每个学生的作答(1=对 0=错):")
for i in range(6):
print(" S%-3d " % (i+1) + "".join(str(v) for v in data[i]))
print(" ...")
# ================= 对数似然 =================
def log_lik(data, p_l0, p_t, p_g, p_s):
"""整批数据的对数似然:每个学生独立,逐题用 BKT 前向算法累积"""
ll = 0.0
for row in data:
p = p_l0
for o in row:
pc = p * (1 - p_s) + (1 - p) * p_g # 预测:答对的概率
ll += np.log(pc if o else 1 - pc) # 累加该观测的对数概率
# ---- 以下与预测无关,只是把信念推进到下一题 ----
if o:
post = p * (1 - p_s) / pc
else:
post = p * p_s / (1 - pc)
p = post + (1 - post) * p_t
return ll
ll_true = log_lik(data, TRUE["l0"], TRUE["t"], TRUE["g"], TRUE["s"])
print()
print("真参数下的对数似然 = %.2f" % ll_true)
# ================= 网格搜索:哪一组参数最好? =================
grid = np.arange(0.05, 1.0, 0.05)
rows = []
for l0 in grid:
for t in grid:
for g in grid:
for s in grid:
if g + s >= 1.0: # 排除退化区(猜对+失误 ≥ 1 没有意义)
continue
rows.append((log_lik(data, l0, t, g, s), l0, t, g, s))
rows.sort(reverse=True)
print("网格搜索了 %d 组参数(4 个参数各 19 档)" % len(rows))
print()
print("=== 对数似然最高的 8 组参数 ===")
print(" 排名 对数似然 P(L0) P(T) P(G) P(S)")
for k, (ll, l0, t, g, s) in enumerate(rows[:8], 1):
print(" %2d %8.2f %.2f %.2f %.2f %.2f" % (k, ll, l0, t, g, s))
print()
best_ll = rows[0][0]
print("=== 对数似然在最优值 5.0 分以内的所有参数组 ===")
near = [r for r in rows if r[0] >= best_ll - 5.0]
print("共 %d 组(占全部 %.1f%%)" % (len(near), 100*len(near)/len(rows)))
print("这些解里,P(T) 的取值范围:%.2f ~ %.2f"
% (min(r[2] for r in near), max(r[2] for r in near)))
print("这些解里,P(G) 的取值范围:%.2f ~ %.2f"
% (min(r[3] for r in near), max(r[3] for r in near)))
实跑输出
模拟数据:100 个学生 × 8 道题,总正确率 0.584
每个学生的作答(1=对 0=错):
S1 00011111
S2 11101101
S3 11111011
S4 01111111
S5 11111111
S6 01000000
...
真参数下的对数似然 = -434.40
网格搜索了 61731 组参数(4 个参数各 19 档)
=== 对数似然最高的 8 组参数 ===
排名 对数似然 P(L0) P(T) P(G) P(S)
1 -433.72 0.35 0.10 0.20 0.10
2 -433.90 0.40 0.10 0.20 0.10
3 -434.40 0.30 0.10 0.20 0.10
4 -434.87 0.45 0.10 0.20 0.10
5 -435.09 0.35 0.10 0.25 0.10
6 -435.48 0.30 0.10 0.25 0.10
7 -435.52 0.40 0.10 0.25 0.10
8 -435.97 0.40 0.10 0.15 0.10
=== 对数似然在最优值 5.0 分以内的所有参数组 ===
共 44 组(占全部 0.1%)
这些解里,P(T) 的取值范围:0.05 ~ 0.15
这些解里,P(G) 的取值范围:0.15 ~ 0.25
好消息:真参数 $P(L_0)=0.30, P(T)=0.10, P(G)=0.20, P(S)=0.10$
在最优 8 组里排第 3,对数似然只比最优差 0.68。拟合是成功的。
坏消息(也是这一节真正要讲的):44 组参数的似然都在最优值 5 分以内,
而这 44 组里 $P(T)$ 从 0.05 到 0.15,$P(G)$ 从 0.15 到 0.25。
也就是说:同样一份数据,能支持"学习率只有 0.05"和"学习率高达 0.15"两个结论,
相差三倍。
4.5.3 ⭐ 这个"分不开"到底有多严重:两个世界
"参数有不确定性"是统计学常识,所以上面那个结果本身不惊人。
真正吓人的是下一步:两组似然几乎一样、预测也几乎一样好的参数,
对学生个体的结论可以完全不同。下面把这件事算出来。
import numpy as np
rng = np.random.default_rng(7)
def simulate(p_l0, p_t, p_g, p_s, n_stu, n_item, rng):
data = np.zeros((n_stu, n_item), dtype=int)
for i in range(n_stu):
know = rng.random() < p_l0
for j in range(n_item):
data[i, j] = rng.random() < ((1 - p_s) if know else p_g)
if not know:
know = rng.random() < p_t
return data
TRUE = (0.30, 0.10, 0.20, 0.10) # (L0, T, G, S)
train = simulate(*TRUE, 100, 8, rng)
test = simulate(*TRUE, 100, 8, np.random.default_rng(99))
def predict_and_mastery(data, p_l0, p_t, p_g, p_s):
"""返回:每个观测的预测 P(答对);每个学生做完后的 P(掌握)"""
preds, mastery = [], []
for row in data:
p = p_l0
for o in row:
pc = p * (1 - p_s) + (1 - p) * p_g
preds.append(pc)
post = (p * (1 - p_s) / pc) if o else (p * p_s / (1 - pc))
p = post + (1 - post) * p_t
mastery.append(p)
return np.array(preds), np.array(mastery)
def auc(scores, labels):
"""AUC = P(随机取一个正样本,得分高于随机取一个负样本)。用秩和公式手算。"""
order = np.argsort(scores, kind="stable")
ranks = np.empty(len(scores)); ranks[order] = np.arange(1, len(scores) + 1)
n_pos = labels.sum(); n_neg = len(labels) - n_pos
return (ranks[labels == 1].sum() - n_pos * (n_pos + 1) / 2) / (n_pos * n_neg)
def rmse(p, y): return float(np.sqrt(np.mean((p - y) ** 2)))
# 两个"几乎一样好"的世界:学习率差 3 倍,初始掌握率差 2 倍
A = (0.30, 0.05, 0.20, 0.10) # 学得慢的世界
B = (0.30, 0.15, 0.20, 0.10) # 学得快的世界
for name, P in (("A 学得慢 T=0.05", A), ("B 学得快 T=0.15", B)):
tr_p, _ = predict_and_mastery(train, *P)
te_p, te_m = predict_and_mastery(test, *P)
print("%s:训练集对数似然 %.2f | 测试集 AUC %.4f | 测试集 RMSE %.4f"
% (name, float(np.sum(np.log(np.where(train.ravel()==1, tr_p, 1-tr_p)))),
auc(te_p, test.ravel().astype(bool)), rmse(te_p, test.ravel())))
print()
_, mA = predict_and_mastery(test, *A)
_, mB = predict_and_mastery(test, *B)
print("—— 但两个世界对这些学生的结论不同 ——")
print("最后 P(掌握) 的相关:r = %.3f" % np.corrcoef(mA, mB)[0,1])
print("平均 P(掌握): A 世界 %.3f | B 世界 %.3f" % (mA.mean(), mB.mean()))
thr = 0.95
print("用'P(掌握)>%.2f 就算学会了'做判断:" % thr)
print(" A 世界判定学会 %d 人,B 世界判定学会 %d 人,判断不一致的有 %d 人(%.0f%%)"
% ((mA>thr).sum(), (mB>thr).sum(), ((mA>thr) != (mB>thr)).sum(),
100*((mA>thr) != (mB>thr)).mean()))
print()
print("两个世界对'熟练所需练习次数'的预测:")
for name, P in (("A", A), ("B", B)):
p, n = P[0], 0
while p < 0.95 and n < 1000:
p = p + (1 - p) * P[1]; n += 1
print(" %s 世界:从 P(L0)=%.2f 练到 P(L)=0.95 需要 %d 次" % (name, P[0], n))
实跑输出
A 学得慢 T=0.05:训练集对数似然 -439.61 | 测试集 AUC 0.7646 | 测试集 RMSE 0.4371
B 学得快 T=0.15:训练集对数似然 -436.39 | 测试集 AUC 0.7711 | 测试集 RMSE 0.4381
—— 但两个世界对这些学生的结论不同 ——
最后 P(掌握) 的相关:r = 0.973
平均 P(掌握): A 世界 0.611 | B 世界 0.714
用'P(掌握)>0.95 就算学会了'做判断:
A 世界判定学会 41 人,B 世界判定学会 51 人,判断不一致的有 10 人(10%)
两个世界对'熟练所需练习次数'的预测:
A 世界:从 P(L0)=0.30 练到 P(L)=0.95 需要 52 次
B 世界:从 P(L0)=0.30 练到 P(L)=0.95 需要 17 次
请把这张输出读三遍。它是这一整页里最重要的东西。
训练对数似然 测试 AUC 测试 RMSE "练到 95% 需要几次"
A -439.61 0.7646 0.4371 52 次
B -436.39 0.7711 0.4381 17 次
差值 3.22 0.0065 0.0010 3 倍
- 在"模型好不好"的所有常规指标上,A 和 B 几乎无法区分:
对数似然差 3.2(在总对数似然 440 的量级上),AUC 差 0.0065,RMSE 差 0.001。
如果你按教科书流程做模型选择,你会说"两个模型差不多,选 B 吧,似然略高"。 - 但 A 和 B 对同一个学生的判断不一致的有 10%(10 个学生,
在"这个学生到底学会没有"这件事上给出相反答案)。 - 最刺眼的是最后一行:A 世界说"这个技能要练 52 次才能熟练",
B 世界说"17 次就行"。差了整整三倍。
⭐ 如果一个自适应学习系统按 A 的参数运行,它会给你排 52 道题;
按 B 的参数运行,它排 17 道就放你走了。
而这两个系统在你所有能想到的模型评价指标上,表现完全一样。这不是 BKT 的缺陷,这是所有"从数据反推隐状态"的模型的处境。
数据只能把参数约束到一个区域,不能约束到一个点;
而在那个区域里挑哪个点,靠的是先验、正则化、或者外部约束,
也就是数据之外的东西。
顺便注意那个 $r = 0.973$。两个世界对学生掌握度的估计高度相关。
所以"相关高"根本不能当"结论一致"的证据,
两个世界的排名几乎一样,但"什么时候算学会了"这个绝对判断差得很远。
只看相关系数会完全错过这个问题。
4.5.4 什么时候会变好?
一句话:数据更多、序列更长、学生更多,可辨识性就会变好。
这不是空话,你可以自己改上面代码里的 N_STU 和 N_ITEM 亲眼验证:
把 N_ITEM 从 8 改成 30,你会发现"似然在最优 5 分以内"的参数组里,
$P(T)$ 的范围显著收窄。
但现实里恰恰相反:真实 ITS 里,一个技能通常只被练 5–15 次,
而一个班可能只有 30–100 人。也就是说,真实场景正好落在最不可辨识的那一档。
这就是为什么工程上的知识追踪系统几乎都做了这三件事:
- 加先验 / 加约束(例如强制 $P(S) < 0.5$、$P(G) < 0.5$),
用人先验来填补数据填不上的地方。 - 跨技能共享参数(假设"猜对率"在不同技能间差不多),
用"别的技能的数据"来借力。 - 放弃解释参数,只追求预测(下一节的深度知识追踪就是这条路),
这是一个诚实但代价很大的选择:你得到一个能用的系统,失去对它的理解。
① 预测准和参数对是两件不同的事,前者可以完全不管后者。
② 数据分不开的两个世界,会给出相差三倍的行动建议(52 次 vs 17 次)。
③ 在那个分不开的区域里做选择,靠的是先验,而先验就是假设。
这就是 §1 那个箭头的第三层含义:假设不仅决定了"信号意味着什么",
还决定了"你接下来要做什么"。
4.6 BKT 的已知问题,和它的后继者
BKT 的六条已知毛病(每一条都是真实文献里的批评):
| 问题 | 具体表现 | 本页哪里见过 |
|---|---|---|
| 不遗忘 | 信念饱和后极难回落 | §3.3 压力测试(连错 3 次只掉到 0.964) |
| 单技能假设 | 一道题涉及多个技能时,模型无法分配 | — |
| 参数不可辨识 | 44 组参数同样好;$P(T)$ 差 3 倍 | §3.5.2、§3.5.3 |
| 作答条件独立假设 | 同一学生的连续作答被当成独立,忽略了"题与题的相似性" | — |
| 每个技能单独建模 | 技能数多了以后,参数总数爆炸,且每个技能的样本更少 | §3.5.4 |
| 对"猜"的建模过于简单 | 把 $P(G)$ 当成常数,不区分"部分知识"(学生可能只掌握了一半) | — |
"部分知识"那条值得多说一句:BKT 的隐状态只有两个值(会 / 不会)。
但真实的学习是连续的、渐进的,学生经常处于"半会"状态:
能做对简单情形,做不对变式。用二值状态逼真,会把这类学生反复在两端之间甩。
后继者一:带遗忘的扩展。最直接的修法是加一个 $P(F)$(遗忘率),
或者用"个体化先验"(PPS,Prior Per Student)让每个学生有自己的 $P(L_0)$。
但这些扩展会让本来就不好的可辨识性雪上加霜(参数更多了)。
后继者二:深度知识追踪(Deep Knowledge Tracing, DKT)。
Piech 等人在 2015 年提出用 RNN/LSTM 替代 BKT 的显式状态
(Piech, C., et al. (2015). Deep Knowledge Tracing. NeurIPS 2015)。
做法是:把学生的作答序列(题号 + 对错)喂进循环网络,让网络自己学出一个隐藏向量,
用它来预测下一题答对的概率。
它在基准数据上明显优于 BKT,但代价很具体:
- 那个隐藏向量没有心理学解释。它不等于"掌握度",
而且同一个学生的隐藏向量在两次训练之间可以完全不同(不可辨识的问题换了个地方出现)。 - 它常常"预测得更准,但结论更怪":有研究发现 DKT 学出的状态会不单调,
学生答对一题之后,预测的答对概率反而下降(因为网络在追踪别的东西)。 - 参数更多 → 需要更多数据 → 小规模教学场景反而更差。
⭐ 这是本页反复出现的一个模式:更强的模型买到的是更好的预测,
不一定买到更好的理解。而教育决策需要的是理解,
你没法向家长解释"神经网络觉得他该重读"。
工业界用 DKT,学术界还在用 BKT 做可解释的推断,这个分裂是有道理的。
4.7 边界与批评
- BKT 是"技能级"模型,不是"人级"模型。它追踪的是"这个学生对这道技能"的状态,
不是"这个学生的能力"。把两者混起来会导致很荒谬的结论(比如"这个学生数学能力 = 0.62")。 - 所有 KT 方法都依赖"技能标注"(哪道题考哪个技能)。这份标注通常是人手工做的,
而它的质量极少被报告。标注错了,上面所有公式都在算错的东西。 - "答对"这个标签本身可能是脏的:抄袭、蒙、提示后答对、看答案后答对,
这些都会让 $P(G)$ 被严重低估(模型以为他猜的,其实他抄的)。
知识追踪把"会不会"成功地变成了一个可计算的量,
代价是它必须先假装"会不会"是一个二值的、不遗忘的、每道题只考一个技能的东西。
5 学习分析(三):怎么评价一个教育模型,以及为什么准确率不够
上一节我们已经用到 AUC 和 RMSE 了。这一节把它们讲清楚,
然后讲这门课最实用的一节:为什么一个"准确率很高"的教育模型可能毫无价值。
5.1 AUC 与 RMSE:两个指标,两种问法
先分清这两个指标问的是不同的问题:
| 指标 | 问的问题 | 值的范围 | 对"基准率"敏感吗 |
|---|---|---|---|
| RMSE | 你预测的概率,离真实结果有多远? | $[0, 1]$(这里是二分类) | 敏感(类别不平衡会压低它) |
| AUC | 你排序的能力有多好? | $[0.5, 1]$(0.5 = 瞎猜) | 不敏感 |
RMSE 的定义(就是"预测概率与真实结果之差的平方,取平均,再开根号"):
$$\mathrm{RMSE} = \sqrt{\frac{1}{N}\sum_{i=1}^{N}(p_i - y_i)^2}, \qquad y_i \in \{0,1\},\ p_i \in [0,1]$$
逐项读:$p_i$ 是模型给第 $i$ 个观测的"答对概率",$y_i$ 是实际的对错。
$p_i - y_i$ 就是这一次预测的误差,平方是为了不让正负误差互相抵消,
开根号是为了让单位回到"概率"这个量纲上(否则你没法说"误差是 0.2 平方概率"这种怪话)。
AUC 的定义(这个定义必须背下来,因为它解释了 AUC 为什么"与阈值无关"):
$$\mathrm{AUC} = P\bigl(\text{随机取一个正样本和一个负样本,正样本的得分更高}\bigr)$$
逐项读:注意它只说"排序",不说"分数是多少"。
所以一个模型把所有分数都加上 100,AUC 完全不变;
一个模型把所有人预测成 30% 概率,AUC 就是 0.5(因为它没有排序能力)。
计算 AUC 有一个手算可用的公式(等价于 Mann-Whitney U 检验):
$$\mathrm{AUC} = \frac{\sum_{i \in \text{正}} r_i - \dfrac{n_+ (n_+ + 1)}{2}}{n_+ \, n_-}$$
其中 $r_i$ 是第 $i$ 个正样本在全体样本按得分排序后的秩,
$n_+$ / $n_-$ 是正负样本数。
逐项读:分子是"正样本的秩之和"减去"如果正样本全排在最前面,它们的秩之和会是多少"。
这个差值就是"正样本比'完美排序'多占了多少排名位"。
除以 $n_+ n_-$(所有正负配对数)就归一化到 $[0,1]$ 了。
正样本排得越靠前,$\sum r_i$ 越大,AUC 越接近 1。
下面手算 AUC,并用暴力配对法核对。
import numpy as np
rng = np.random.default_rng(3)
def auc(scores, labels):
"""秩和公式(Mann-Whitney U)。并列得分取平均秩,保证与定义式一致。"""
order = np.argsort(scores)
ranks = np.empty(len(scores))
s_sorted = scores[order]
i = 0
while i < len(s_sorted): # 手工处理并列:同分取平均秩
j = i
while j + 1 < len(s_sorted) and s_sorted[j + 1] == s_sorted[i]:
j += 1
ranks[order[i:j + 1]] = (i + j) / 2 + 1
i = j + 1
n_pos = labels.sum(); n_neg = len(labels) - n_pos
return (ranks[labels == 1].sum() - n_pos * (n_pos + 1) / 2) / (n_pos * n_neg)
def auc_bruteforce(scores, labels):
"""定义式:所有 (正, 负) 配对里,正样本得分更高的比例"""
pos = scores[labels == 1]; neg = scores[labels == 0]
return float((pos[:, None] > neg[None, :]).mean() + 0.5 * (pos[:, None] == neg[None, :]).mean())
# ---------- 一个典型的"预测谁会挂科"场景 ----------
N = 2000
base_rate = 0.08 # 8% 的学生最终挂科(真实场景里通常很低)
y = rng.random(N) < base_rate
# 模型给出的风险分数:挂科的人分数略高,但重叠很大(现实中的典型水平)
score = rng.random(N) * 0.6 + y * rng.normal(0.35, 0.25, N) + rng.normal(0, 0.2, N)
score = np.clip(score, 0, 1)
a1 = auc(score, y); a2 = auc_bruteforce(score, y)
print("=" * 70)
print("① AUC 的两种算法必须一致(秩和公式 vs 定义式暴力配对)")
print("=" * 70)
print(" 秩和公式算得 AUC = %.4f" % a1)
print(" 暴力配对算得 AUC = %.4f" % a2)
print(" 配对总数 = %d 正 × %d 负 = %d 对" % (y.sum(), (1-y).sum(), y.sum()*(1-y).sum()))
print()
print(" AUC 的准确含义:随机抽一个'真挂科'的和一个'真没挂科'的,")
print(" 模型的分数把挂科那个排在前面的概率 = %.1f%%" % (100*a1))
print()
print("=" * 70)
print("② 同一个模型,换个阈值,有用程度天差地别")
print("=" * 70)
print(" AUC 与阈值无关(它是全局的排序质量),但干预必须选阈值。")
print()
print(" 阈值 预警人数 命中(真挂科) 误报 精确率 召回率")
for thr in (0.9, 0.7, 0.5, 0.4, 0.3, 0.2):
pred = score > thr
tp = int((pred & y).sum()); fp = int((pred & ~y).sum()); fn = int((~pred & y).sum())
prec = tp / (tp + fp) if tp + fp else float('nan')
rec = tp / (tp + fn) if tp + fn else float('nan')
print(" %.1f %6d %6d %6d %.3f %.3f" % (thr, pred.sum(), tp, fp, prec, rec))
print()
print(" ⚠️ 阈值 0.9:名单最干净(命中率 56.9%),但只覆盖了 18.8% 的挂科学生——")
print(" 五分之四的人漏掉了,这个'预警系统'基本没起到预警作用。")
print(" ⚠️ 阈值 0.2:覆盖了 85.8% 的挂科学生,但预警名单 1311 人(占全校 66%),")
print(" 其中 88.5% 是误报——老师不可能去'救'一千多个不会挂科的学生。")
print(" ⭐ 两个阈值之间不存在'都对'的选项:要么漏,要么淹。")
print()
print(" ⭐ 这就是'预测准确率高 ≠ 教学有用'的算术版本:")
print(" 挂科率只有 %.0f%%(先验很低),任何'宁可错杀'的策略都会被误报淹没。" % (100*base_rate))
print()
print("=" * 70)
print("③ 相同的 AUC,在不同的基准率下,精确率完全不同")
print("=" * 70)
print(" 基准率 AUC 阈值=0.5 时的精确率 阈值=0.5 时的召回率")
for br in (0.02, 0.08, 0.20, 0.50):
yy = rng.random(N) < br
ss = np.clip(rng.random(N)*0.6 + yy*rng.normal(0.35,0.25,N) + rng.normal(0,0.2,N), 0, 1)
pred = ss > 0.5
tp = int((pred & yy).sum()); fp = int((pred & ~yy).sum()); fn = int((~pred & yy).sum())
prec = tp/(tp+fp) if tp+fp else float('nan')
rec = tp/(tp+fn) if tp+fn else float('nan')
print(" %.2f %.4f %.3f %.3f" % (br, auc(ss, yy), prec, rec))
print()
print(" AUC 几乎没变,但精确率从不到 0.1 涨到 0.7 —— ")
print(" 因为精确率强烈依赖基准率,而 AUC 对基准率不敏感。")
print(" 所以引用'我们模型 AUC = 0.9'时,必须先问:挂科率是多少?")
实跑输出
======================================================================
① AUC 的两种算法必须一致(秩和公式 vs 定义式暴力配对)
======================================================================
秩和公式算得 AUC = 0.7588
暴力配对算得 AUC = 0.7588
配对总数 = 176 正 × 1824 负 = 321024 对
AUC 的准确含义:随机抽一个'真挂科'的和一个'真没挂科'的,
模型的分数把挂科那个排在前面的概率 = 75.9%
======================================================================
② 同一个模型,换个阈值,有用程度天差地别
======================================================================
AUC 与阈值无关(它是全局的排序质量),但干预必须选阈值。
阈值 预警人数 命中(真挂科) 误报 精确率 召回率
0.9 58 33 25 0.569 0.188
0.7 221 73 148 0.330 0.415
0.5 551 111 440 0.201 0.631
0.4 796 133 663 0.167 0.756
0.3 1061 144 917 0.136 0.818
0.2 1311 151 1160 0.115 0.858
⚠️ 阈值 0.9:名单最干净(命中率 56.9%),但只覆盖了 18.8% 的挂科学生——
五分之四的人漏掉了,这个'预警系统'基本没起到预警作用。
⚠️ 阈值 0.2:覆盖了 85.8% 的挂科学生,但预警名单 1311 人(占全校 66%),
其中 88.5% 是误报——老师不可能去'救'一千多个不会挂科的学生。
⭐ 两个阈值之间不存在'都对'的选项:要么漏,要么淹。
⭐ 这就是'预测准确率高 ≠ 教学有用'的算术版本:
挂科率只有 8%(先验很低),任何'宁可错杀'的策略都会被误报淹没。
======================================================================
③ 相同的 AUC,在不同的基准率下,精确率完全不同
======================================================================
基准率 AUC 阈值=0.5 时的精确率 阈值=0.5 时的召回率
0.02 0.8008 0.059 0.718
0.08 0.7860 0.196 0.677
0.20 0.7867 0.430 0.671
0.50 0.7800 0.724 0.668
AUC 几乎没变,但精确率从不到 0.1 涨到 0.7 ——
因为精确率强烈依赖基准率,而 AUC 对基准率不敏感。
所以引用'我们模型 AUC = 0.9'时,必须先问:挂科率是多少?
三点解读:
- 两种算法算出的 AUC 完全一致(0.7588)。说明秩和公式和定义式是同一个东西,
这一步值得每次自己做一遍,因为 AUC 是那种"用错了一整年都不会发现"的指标
(它永远不会报错,只会给你一个看起来合理的数)。⚠️ 注意并列得分要取平均秩,
否则秩和公式和定义式会差一点点(我第一次跑就差了 0.0005,原因是并列被随意排序了)。 - 阈值 0.9 那行:精确率 0.569 看起来不错,但召回率只有 0.188。
这意味着这个"精准的预警系统"漏掉了 81% 的挂科学生。
只报精确率不报召回率,是教育预警类论文里最常见的包装手法。 - 第三部分(基准率实验)是最狠的。四组数据的 AUC 几乎一样(0.78–0.80),
但阈值 0.5 下的精确率从 0.059 一路涨到 0.724。
同一个模型,同一个 AUC,在挂科率 2% 的学校和挂科率 50% 的学校,
实际可用性差了一个数量级。
5.2 精确率、召回率,和"基准率"这个隐形变量
把上面用到的三个量定义清楚:
| 量 | 公式 | 问的问题 | 依赖基准率吗 |
|---|---|---|---|
| 精确率(precision) | $\dfrac{TP}{TP+FP}$ | 预警名单里,有多少是真的? | 强烈依赖 |
| 召回率(recall) | $\dfrac{TP}{TP+FN}$ | 真正该预警的人里,抓到了多少? | 不依赖 |
| 准确率(accuracy) | $\dfrac{TP+TN}{N}$ | 总共对了多少? | 强烈依赖 |
为什么精确率依赖基准率? 因为它分母里有个 $FP$(误报),
而 $FP$ 的数量大致等于"负样本总数 × 误报率"。
当负样本占绝大多数时(挂科率低),$FP$ 会被这个巨大的基数硬撑起来,
于是精确率被压得很低。这是本节输出第三部分的全部道理。
⚠️ 而"准确率"是三者里最不该单独用的一个。回到 §2.2 那个例子:
预测准确率 0.676、基准线 0.647,而基准线的 0.647 是"永远猜多数类"就能拿到的。
一个连"永远猜多数类"都赢不了多少的模型,报"准确率 67.6%"是在说什么呢?
⭐ 一句话总结这一小节:教育数据的基准率通常很低(挂科、退课、需要干预都是少数事件),
而这恰恰是"准确率"和"精确率"最容易骗人的场景。
低基准率 + 只报准确率 = 一个可以在任何数据集上做出漂亮数字的组合。
5.3 ⭐ 准确率高 ≠ 教学有用:四条理由
这一小节是本节的核心,也是《实验方法论》里"指标决定结论"的直接应用。
"模型准确率高所以对学生有帮助"这个推论,在四个地方会断:
理由一:预测的目标和教学的目标不是同一个。
模型被训练去预测"不干预的情况下会发生什么",而教学的目标是改变它。
这两件事在数学上是相反的:
一个准确率 100% 的预测模型,意味着它完全预测了不干预的后果,
而这恰好意味着干预完全无效(如果干预有效,预测就不准了)。
这叫"预测-干预悖论":模型越准,说明现状越难改变。
理由二:准确率高不代表可行动。
"这个学生有 82% 概率挂科"这句话里没有动作。
要让预测有用,你必须同时说明:做什么?对谁做?做了之后概率会降到多少?
而后面这三个问题,数据一个都回答不了,它们需要随机对照实验
(见《实验方法论》:只有随机化才能谈因果)。
一个没有配套 RCT 的预测模型,本质上是一个"关于未来的统计描述",不是干预方案。
理由三:指标的粒度常常不对。
模型报"整体 AUC = 0.85",但学校真正关心的是"在少数群体学生上表现如何"。
一个整体很好的模型,在样本量小的子群上可能完全是抛硬币,
而恰恰是这些子群最需要帮助。按子群报告性能,是伦理要求,也是技术要求。
理由四:优化指标会改变系统行为(古德哈特定律)。
"当一个指标变成目标,它就不再是一个好指标。"(Goodhart's law,常见表述)
如果学校按"预警系统的召回率"考核老师,老师会去干预更多人;
干预变多之后,被干预本身改变了学生的行为,于是下一轮训练数据的分布变了,
模型报的准确率不再衡量它原来的那个东西。
教育场景特别容易踩这个坑,因为学生是会学习和反应的。
一张"读预测报告"的问题清单(这张表建议抄下来,以后读任何模型报告都能用):
| 该问的问题 | 为什么问 | 本页哪里讲过 |
|---|---|---|
| 基准率是多少? | 决定精确率的量级 | §4.1 第三部分 |
| 基准线模型是多少? | "永远猜多数类"能拿多少分 | §2.2 输出 |
| 阈值怎么选的? | 换阈值就换结论 | §4.1 第二部分 |
| 用什么指标? | 准确率/精确率/AUC 各有各的骗法 | §4.2 |
| 预测的是哪个时间点? | 预测"期末挂科"和"下周挂科"难度天差地别 | — |
| 分群报告了吗? | 少数群体常常被整体指标掩盖 | 理由三 |
| 干预是什么?有 RCT 吗? | 没有干预的预测不是产品 | 理由二 |
| 训练数据覆盖谁? | 缺失的人(退学的、没登录的)常常恰恰是最该关心的 | §2.4 |
5.4 一个附带收获:学习曲线里也有同一个问题
学习分析里常要拟合"练习次数 → 表现"的曲线(用来预测"还要练几次")。
这个拟合里藏着和 §3.5 一模一样的可辨识性问题,而且这是一个真实的学术争议。
import numpy as np
from scipy.optimize import curve_fit
rng = np.random.default_rng(11)
# ============ 一组"练习曲线"数据:随练习次数增加,正确率上升 ============
n = np.arange(1, 31) # 30 次练习
p_true = 0.95 - 0.75 * n ** (-0.55) # 用幂律生成"真值"
trials = 60 # 每个练习点 60 次尝试
k = rng.binomial(trials, p_true)
p_obs = k / trials # 观测到的正确率
print("练习次数 1 3 5 10 15 20 25 30")
print("正确率 " + "".join("%.2f " % p for p in p_obs[[0,2,4,9,14,19,24,29]]))
print()
# ============ 两个候选模型 ============
def power(n, a, b, c): return a - b * n ** (-c) # 幂律:a 是天花板
def expo(n, a, b, c): return a - b * np.exp(-c * n) # 指数:a 是天花板
pp, _ = curve_fit(power, n, p_obs, p0=[1.0, 0.8, 0.5], maxfev=20000)
pe, _ = curve_fit(expo, n, p_obs, p0=[1.0, 0.8, 0.1], maxfev=20000)
def rmse(pred): return float(np.sqrt(np.mean((pred - p_obs) ** 2)))
rp, re_ = rmse(power(n, *pp)), rmse(expo(n, *pe))
print("=" * 68)
print("两个模型在同一组数据上的拟合")
print("=" * 68)
print(" 幂律 P(n) = %.3f - %.3f · n^(-%.3f) RMSE = %.4f" % (pp[0], pp[1], pp[2], rp))
print(" 指数 P(n) = %.3f - %.3f · e^(-%.3f·n) RMSE = %.4f" % (pe[0], pe[1], pe[2], re_))
print()
print(" 两者的 RMSE 差异:%.4f (相对差 %.1f%%)" % (abs(rp - re_), 100*abs(rp-re_)/max(rp, re_)))
print()
# ============ 外推:两个模型在"没见过的练习次数"上分歧巨大 ============
print("=" * 68)
print("外推:在训练数据之外(n = 60 / 100 / 200),两个模型的分歧")
print("=" * 68)
print(" n 幂律预测 指数预测 差值")
for nn in (10, 30, 60, 100, 200):
a, b = float(power(nn, *pp)), float(expo(nn, *pe))
print(" %3d %.4f %.4f %+.4f" % (nn, a, b, a - b))
print()
inrange = np.abs(power(n, *pp) - expo(n, *pe))
print(" 在 n ≤ 30(有数据的范围)内,两条曲线的最大差距只有 %.4f(%.1f 个百分点)"
% (inrange.max(), 100*inrange.max()))
print(" 而观测数据本身的抽样波动(60 次尝试的二项噪声)标准差约 %.3f。" % np.sqrt(0.8*0.2/60))
print(" ——两个模型的差距,和数据自身的噪声一样大。")
print()
print(" ⭐ 出了 n=30 这个范围,两条曲线分道扬镳,越走越远——")
print(" 但数据没有资格告诉你该信哪一个。")
print()
print(" ⭐ 这正是 Heathcote, Brown & Mewhort (2000) 的真实论点:")
print(" 练习数据的'幂律'和'指数律'之争,很大程度上不是数据之争,")
print(" 而是'你默认了哪个函数族'之争。")
实跑输出
练习次数 1 3 5 10 15 20 25 30
正确率 0.15 0.52 0.70 0.72 0.83 0.80 0.85 0.88
====================================================================
两个模型在同一组数据上的拟合
====================================================================
幂律 P(n) = 0.875 - 0.726 · n^(-0.757) RMSE = 0.0502
指数 P(n) = 0.791 - 0.933 · e^(-0.427·n) RMSE = 0.0563
两者的 RMSE 差异:0.0061 (相对差 10.8%)
====================================================================
外推:在训练数据之外(n = 60 / 100 / 200),两个模型的分歧
====================================================================
n 幂律预测 指数预测 差值
10 0.7476 0.7776 -0.0299
30 0.8194 0.7906 +0.0287
60 0.8419 0.7906 +0.0513
100 0.8524 0.7906 +0.0618
200 0.8615 0.7906 +0.0709
在 n ≤ 30(有数据的范围)内,两条曲线的最大差距只有 0.0518(5.2 个百分点)
而观测数据本身的抽样波动(60 次尝试的二项噪声)标准差约 0.052。
——两个模型的差距,和数据自身的噪声一样大。
⭐ 出了 n=30 这个范围,两条曲线分道扬镳,越走越远——
但数据没有资格告诉你该信哪一个。
⭐ 这正是 Heathcote, Brown & Mewhort (2000) 的真实论点:
练习数据的'幂律'和'指数律'之争,很大程度上不是数据之争,
而是'你默认了哪个函数族'之争。
这个结果的读法和 §3.5.3 完全一样:
- 在有数据的范围内($n \le 30$),两个模型的差距是 0.0518,
而数据自身的抽样噪声标准差是 0.052。两个模型的差距和数据噪声一样大。 - 出了这个范围,它们分歧越来越大(到 $n=200$ 时差 0.07,而且方向稳定)。
- 而"该信哪个"这个问题,数据没资格回答。
这不是一个玩具问题,它是一场真实的学术争论:
心理学的"练习律"(practice law)长期被认为是幂律(Newell & Rosenbloom 1981),
Heathcote、Brown 和 Mewhort 在 2000 年发表《The power law repealed》,
主张大多数练习数据其实是指数律,而过去的"幂律"结论部分是拟合方法和平均方式造成的假象
(Heathcote, Brown & Mewhort (2000), Psychonomic Bulletin & Review, 7(2), 185–207)。
⭐ 把这一节和 §3.5 放在一起看,你会发现两门课的方法论是同一套:
"数据支持哪个模型"这个问题,在没有额外约束的时候,
答案取决于你允许哪些模型进入候选集,而候选集是你定的。
5.5 边界与批评
- AUC 不是万能的:它在极度不平衡时会显得虚高(因为负样本太多,
随便排排也能赢很多配对)。不平衡时应该看 PR 曲线(精确率-召回率曲线)。 - RMSE 对概率校准敏感、对排序不敏感:两个模型可以 RMSE 差不多但一个校准很好、
一个完全没校准。教育决策(比如"要不要干预")依赖校准,所以必须单独检查。 - 所有指标都假设"标签是对的":但"挂科"这个标签本身受政策、疫情、老师给分习惯影响。
用错误的标签训练出的模型,指标的精确度毫无意义(garbage in, garbage out)。
教育模型的指标必须连同它的基准线、阈值、基准率和干预方案一起报。
单独一个"准确率 0.9",信息量约等于零。
6 学习分析(四):伦理与隐私(这一节不是点缀)
为什么这一节必须写? 因为它不是"技术之外的道德补充",
而是技术本身长出来的问题。理由很直接:
学习分析的对象是未成年人或刚成年的学生,收集的是他们最没有议价能力时产生的数据,
而输出的结论("高风险"、"低投入")会直接影响他们的机会。
换成任何其他领域,这套组合都会立刻被质疑;只有教育领域,它常常被当成"科技赋能"。
6.1 数据从哪来,边界在哪
把 §2.3 那张表扩展一下,加上"学生知道吗"和"能拒绝吗"两列,情况立刻变糟:
| 数据 | 产生方式 | 学生知道吗 | 能拒绝吗 |
|---|---|---|---|
| LMS 点击流 | 使用平台时自动产生 | 通常不知道具体粒度 | 不能(不用平台就没法学) |
| 作答记录 | 做作业产生 | 知道有分数 | 不能(作业是必须做的) |
| 用时/修改次数 | 自动记录 | 基本不知道 | 不能 |
| 眼动/面部 | 需要专门设备 | 知道(要戴设备/坐摄像头前) | 理论上能,实际有压力 |
| 设备与网络信息 | 自动记录 | 不知道 | 不能 |
关键的结构性问题是:学习数据的采集和使用,几乎是"全有或全无"的。
你没法"只用 LMS 的一半功能"。这和无数的商业 App 一样,
但教育场景的强制性更高,学生没有"换个平台"的选项。
⚠️ "知情同意"在教育场景里尤其可疑。一份写在用户协议第 14 页的条款,
由一个 18 岁的新生点"同意",这算同意吗?
而且很多数据是在学生还没成年时收集的(高中阶段的平台数据),
到了大学仍然在影响他。
6.2 五类真实议题
议题一:预测的自我实现。
模型预测"这个学生高风险"
↓
老师/系统对ta区别对待(劝退、降级、减少投入)
↓
学生真的表现更差
↓
"看,模型预测得很准"
这个循环的可怕之处在于它会让模型显得越来越准,同时让伤害越来越真实。
要打破它,唯一的方法是保留一个"没有被干预"的对照组,
而学校出于伦理,恰恰不应该对高风险学生"不干预"。
这是学习分析里最深的伦理-技术纠缠:你想验证模型,就得让一部分人不被帮助。
(出路一般是随机化"干预方式"而不是"干预与否",见《实验方法论》的 RCT 章节。)
议题二:标签的持久性与不可申诉。
一次预测给出"高风险"标签,它写进系统,
可能跟着这个学生走好几年,而学生不知道、也无法申诉。
Slade 和 Prinsloo 在讨论学习分析伦理时特别强调学生身份的"暂时性、时间性和情境依赖性",
一个 19 岁新生的学习状态,不应该被冻结成一个永久的属性
(Slade, S., & Prinsloo, P. (2013). Learning analytics: Ethical issues and dilemmas.
American Behavioral Scientist, 57(10), 1510–1529)。
议题三:代理变量的歧视。
模型不用"种族/户籍/家庭收入"做特征,但它用"登录时间"和"设备类型",
而这两个变量与家庭条件高度相关。
这叫代理歧视(proxy discrimination):你去掉了敏感变量,
但你的其他变量把它编码进去了。
这是学习分析里技术上最难、也最少被认真处理的问题。
议题四:二次使用。
数据最初为"改进教学"收集,后来被用来"科研""发表""产品迭代""卖给第三方"。
每一次扩张都需要重新同意,而现实中通常不会。
这种"功能蔓延"(function creep)是数据伦理里最常见的失效模式。
议题五:权力不对称。
数据的所有权和解释权,几乎全在学校和厂商一侧。
学生不知道自己的哪些数据被用来做了什么判断,
而这些判断会直接影响他能不能毕业、能不能拿到推荐信。
Slade & Prinsloo 明确把权力(power)和监控(surveillance)
列为学习分析伦理的核心维度,不是一个可以在技术方案里"顺便解决"的附带问题。
6.3 态度与出路
这一节不该给你一套"标准答案",因为这些问题都还没有共识。
但它应该给你一个立场:
⭐ 学习分析不是中立的。
它把教学关系里的判断从人转移到了模型上,
而模型做出的判断会被当成"客观的""数据说的",
从而获得了人的判断所没有的权威。
几条实务上的建议(来自上述文献的共识部分):
| 原则 | 具体做法 |
|---|---|
| 透明 | 学生有权知道"系统记录了关于我的什么、用它做了什么判断" |
| 可申诉 | 任何影响学生的自动化判断,必须有人工复核与申诉通道 |
| 最小化 | 只收完成明确目的所必需的数据(别因为"以后可能有用"就全收) |
| 按子群报告 | 模型在被保护子群上的性能必须单独报告(见 §4.3 理由三) |
| 保留不干预组 | 评估干预效果时随机化"干预方式",而不是"是否干预"所有人 |
| 不要把预测当结论 | 输出"建议关注"而不是"高风险",措辞本身影响后续行为 |
国内法规层面:《中华人民共和国个人信息保护法》(2021 年施行)把
不满十四周岁未成年人的个人信息列为敏感个人信息,处理需取得监护人同意。
教育场景的数据处理还涉及《未成年人保护法》的相关规定。
⚠️ 具体的条文细节和各校的合规要求,请以学校法务/伦理委员会的最新说法为准,本页不代替法律意见。
学习分析的技术问题是"能不能算出来",
伦理问题是"算出来之后谁敢用它、用它做什么"。
后面这个问题永远比前面那个难。
7 语言与人脑(一):从"脑区定位"到"脑网络"
从这里开始换到另一半。先重申一次前情,然后立刻往前走:
- 布洛卡区、韦尼克区、弓状束的经典故事、失语症的三个类型、双流模型、
"95% 在左脑"的追溯,这些在《语言认知神经科学》§4–§6 已经讲过,本页不重复。 - 本页要讲的是那套模型之后发生了什么。
7.1 为什么经典模型必须被换掉(三个压力)
经典模型可以压缩成一句话:"两个处理中心 + 一条连接线"。
它在 1874–1990 年代一直是教科书标准答案。但有三股压力最终把它压垮了:
压力一:那两个"中心"自己就不干净。
《语言认知神经科学》§4 讲过 Leborgne 病例的现代重扫(Dronkers et al. 2007):
Broca 那个"证据"的脑子里,损伤远不止布洛卡区,还包括脑岛皮层、基底节和上纵束。
这意味着"布洛卡区 = 言语产生中枢"这个结论,从它被提出的第一天起,
证据就是不合格的。
压力二:功能区在"中心"内部也不是同质的。
现代高分辨率 fMRI 加上逐被试的功能定位发现,
左额下回(所谓"布洛卡区")内部可以分出功能不同的子区域:
有的只对语言反应,有的对一般难任务反应,它们紧挨着但可分离
(Fedorenko, Duncan & Kanwisher (2012), Current Biology, 22(21), 2059–2062:
"Language-selective and domain-general regions lie side by side within Broca's area")。
一个"区域"里装着两种东西,那把它当成一个功能单元就是错的。(§8.2 展开)
压力三:语言不是只在灰质里,也在白质里。
这一条是本节的主线。传导性失语(懂、会说、但不能复述)在《语言认知神经科学》§4 出现过,
它是"白质参与语言"最直接的临床证据。现代弥散成像把这件事推到了新层次:
语言依赖的是一组可以逐条命名的纤维束,而不是一根"弓状束"。
所以现代框架的形态变了:
经典模型(1874 - 1990s) 现代框架(2000s - )
────────────────────── ──────────────────
布洛卡区 一组灰质区域
│ +
弓状束 ──► 一组白质通路
│ +
韦尼克区 动态的功能网络
(谁和谁在什么时候同步)
形态:2 个点 + 1 条线 形态:分布式 + 可分解
7.2 三个现代框架(各管一件事)
现代文献里最常被引的三个框架,回答的是三个不同的问题。
把它们并排看,比单独背任何一个都有用:
| 框架 | 出处 | 回答的问题 | 核心主张 |
|---|---|---|---|
| 双流模型 | Hickok & Poeppel (2004, 2007) | 语言加工分成哪几条流? | 腹侧流 → 理解;背侧流 → 感觉-运动映射 |
| 背-腹通路模型 | Friederici (2011) | 句法和语义分别走哪条路? | 句法走背侧(左偏侧);语义走腹侧(两侧性更强) |
| MUC 模型 | Hagoort (2013, 2019) | 语言除了"词"还有什么? | Memory(记忆)+ Unification(统一)+ Control(控制) |
逐个说清楚,并指出它们的差异。
7.2.1 双流模型(详见《语言认知神经科学》§6)
这里只补一句那页没强调的:双流模型和 Friederici 的模型不是同一个二分。
双流模型分的是"理解 vs 说出来"(功能方向),
Friederici 分的是"语义 vs 句法"(语言学的层次)。
两套切法都可以画成"背侧 + 腹侧",但切的是不同的东西,
这是读文献时最容易混的一处。记法:
双流模型: 腹侧 = "这是什么意思" 背侧 = "怎么说出来"
Friederici: 腹侧 = 词汇-语义 背侧 = 复杂句法
↑ 注意:两个"腹侧"含义相同,两个"背侧"含义不同
7.2.2 Friederici (2011):句法走背侧,语义走腹侧
Friederici, A. D. (2011). The brain basis of language processing: from structure to function.
Physiological Reviews, 91(4), 1357–1392。
它的主张,逐条:
- 句法:由左偏侧化的额-颞网络支持(BA 44 + 后部颞上回/颞上沟)。
在通路层面,复杂句法(层级结构、移位)依赖背侧的弓状束/上纵束。 - 语义:由偏侧化较弱(两侧性更强)的颞-额网络支持。
在通路层面,词汇语义走腹侧通路(见 §6.3)。 - 时间进程:电生理证据显示,局部结构构建(local structure building)
发生在语法与语义关系赋值之前。也就是说"先搭架子,再填内容"。 - 超音段韵律:主要在右半球的颞-额网络加工;
胼胝体后部对句法与韵律信息的交互是必需的。
⚠️ 两条必须补的限定:
- "句法走背侧"说的是"复杂句法"。简单的短语结构(比如"红色的车"这种组合)
走的是腹侧的一条通路。所以"背侧 = 句法"是一个简化;
完整版是"背侧 = 复杂/层级句法"。 - 这个框架来自一个作者的研究纲领,而不是一次中立的元分析。
后来的元分析(Hagoort & Indefrey (2014), Annual Review of Neuroscience, 37, 347–362)
确实支持左额下回和左后颞存在背-腹梯度(背侧偏句法、腹侧偏语义),
但梯度是渐变的,不是锐利的分界。
"渐变"这个更弱的说法,才是证据真正支持的版本。
7.2.3 Hagoort 的 MUC 模型:把"词以上的东西"讲清楚
Hagoort, P. (2013). MUC (Memory, Unification, Control) and beyond.
Frontiers in Psychology, 4, 416。另见 Hagoort, P. (2019).
The neurobiology of language beyond single-word processing. Science, 366(6461), 55–58。
⚠️ 一个容易引错的地方(我核对时纠正了自己原来的印象):
Hagoort 的 2019 年文章发在 Science,不是 Annual Review of Neuroscience。
标题带 "Annual Review" 的那篇(The neurobiology of language beyond single words)
是 Hagoort & Indefrey (2014),而且它不是 MUC 模型的原始出处。
MUC 模型的原始出处是 Hagoort 2013 年的 Frontiers in Psychology 文章
(以及 Hagoort 2005 在 TICS 上的框架文章)。引用时别写成"Annual Review 2019"。
MUC 的三个成分:
| 成分 | 干什么 | 主要脑区 |
|---|---|---|
| Memory(记忆) | 存储词汇-语义知识,需要时检索出来 | 左颞叶(含颞极、颞中/下回) |
| Unification(统一) | 把检索到的词块合并成更大的结构(短语、句子、篇章) | 左额下回(LIFG,即"布洛卡区"那一带) |
| Control(控制) | 根据任务/语境调控上面两个过程 | 前扣带、背侧额叶、顶叶等 |
这个框架的最有价值之处,是它把"从词到句"这件事拆成了两步:
Memory:把"苹果"这个词的意义从记忆里取出来 ← 检索
Unification:把它和"红色的"合并成一个结构 ← 组合
为什么要拆? 因为这两个过程可以在脑上分离:
失语症里有病人能理解单个词,但不能把它们组合起来
(这类症状和左额下回/白质通路的损伤相关)。
"会词不会句"这种情况,只有把"检索"和"组合"分开才能解释。
⭐ MUC 给这一页的最重要提示:"语言区"这个说法本身是有歧义的。
左额下回不是"语言存储区"(存储更靠颞叶),
而是"组合区",它做的是操作,不是存放。
这个区分直接决定了 §8.2 那个问题的答案:
如果一个区域做的是"把任何东西组合起来",那它就不该被叫"语言区"。
7.3 ⭐ 白质通路:逐条讲,并标出哪些是有争议的
这一小节是"语言与人脑"这门课最有信息量、也最容易记错的部分。
我把每条通路都写清楚连接哪里、一般认为管什么、以及证据有多硬。
⚠️ 凡是我无法确认的,直接写"出处待查"或"存在争议"。
先讲一个贯穿全节的困难:人类白质解剖的主要方法是弥散磁共振成像(dMRI)追踪,
而 dMRI 追踪本身有已知的方法学限制,
它无法可靠地确定纤维的起点和终点(纤维靠近皮层时各向异性急剧下降),
也无法在一个体素内分辨交叉的纤维方向。
所以"某条束连接 A 和 B"这类结论,dMRI 单独给出时是不够硬的,
最好有纤维解剖(blunt dissection / Klingler 技术)的交叉验证。
这句话是理解下面所有"有争议"标注的钥匙。
7.3.1 背侧通路
弓状束(arcuate fasciculus, AF)
| 项 | 内容 |
|---|---|
| 连接 | 额下回(岛盖部/三角部,即 BA 44/45)↔ 后部颞叶(后颞上回,及颞中回) |
| 分段 | Catani 等 (2005) 把它分成三段:长直段(额-颞直接连接)、前侧段(额-顶)、后侧段(顶-颞)。这个三段分法来自纤维解剖与追踪的结合 |
| 偏侧化 | 总体左侧优势。Catani 等 (2007) 报告:约 80% 的右利手在长直段上呈左偏侧,约 60% 的正常人呈极端左偏(具体数字随方法和阈值变化,引用时请注明来源) |
| 一般认为管什么 | 复杂句法;语音到发音的映射(感觉-运动);复述 |
| 证据强度 | 较硬。临床(传导性失语)+ 追踪 + 术中电刺激都有支持 |
⚠️ 一个命名上的坑(必须先说清):"弓状束"和"上纵束(SLF)"的边界,
在不同作者那里不一样:
- Catani 等的方案:AF 是额-颞系统(含长直段),SLF 是额-顶系统,两者并列。
- Makris 等的方案(Makris et al. 2005):把 SLF 分成 I–IV 段,
而 AF 就是 SLF IV。也就是说在 Makris 的框架里,AF 是 SLF 的一段,不是并列的束。
所以你在文献里看到"SLF/AF"这种写法是有原因的,
这两套命名至今没有完全统一,看到"SLF III 受损影响句法"和"AF 受损影响句法"
可能说的是同一片纤维。引用时最好说明你用的是哪套分段。
上纵束(superior longitudinal fasciculus, SLF)
| 项 | 内容 |
|---|---|
| 连接 | 额叶 ↔ 顶叶。SLF II 连角回与背侧 BA 6/前额;SLF III 连缘上回与腹侧额区(BA 44,部分 BA 45) |
| 一般认为管什么 | SLF III 参与语音的感觉-运动映射(和背侧流的功能一致) |
| 偏侧化 | ⚠️ 有冲突:Makris 等 (2005) 用 FA 报告所有 SLF 分段均左侧优势;但 Budisavljevic 等 (2017) 用不同指标(流线数、束体积)发现 SLF I/II 左优势、SLF III 右优势,且该结果被后续研究复现。注意:双方用的是不同测量指标,这可能正是结论相反的原因。引用时请标"有争议"。 |
| 证据强度 | 连接存在较硬;偏侧化方向有争议;功能归属较软 |
7.3.2 腹侧通路
额枕下束(inferior fronto-occipital fasciculus, IFOF)
| 项 | 内容 |
|---|---|
| 连接 | 腹内侧枕叶 ↔ 眶额 / 额极皮层(两侧) |
| 一般认为管什么 | 语义加工、跨通道整合;在 Friederici 的框架里,词汇-语义检索的那条腹侧通路常被归到 IFOF / 极端囊纤维系统 |
| ⚠️ 存在性 | 有争议,而且争议不小。在猴的示踪研究中未能证实人类 IFOF 的对应物;人类侧的解剖与追踪文献记录很充分,但"它是不是人类特有"以及"它的精确定义"仍在讨论中(Forkel et al. (2014), Cortex, 56, 73–84,对此有系统梳理;后续综述仍称其解剖与功能"remains contentious") |
| 证据强度 | 存在性有争议(人类内有支持,跨物种不成立);功能归属较软 |
钩束(uncinate fasciculus, UF)
| 项 | 内容 |
|---|---|
| 连接 | 前颞叶(含颞极)↔ 眶额 / 额极 |
| 一般认为管什么 | 语义(尤其是和情境、社会情绪相关的)、情景记忆。在 Friederici 的框架里,局部短语结构的那条腹侧通路经钩束连接额叶岛盖与前部颞上回 |
| 证据强度 | 束的存在较硬;功能归属争议较大(它在很多任务里都出现,不特异) |
下纵束(inferior longitudinal fasciculus, ILF)
| 项 | 内容 |
|---|---|
| 连接 | 枕叶 ↔ 颞叶前部(沿颞叶下缘走行) |
| 一般认为管什么 | 视觉-语义映射(把看到的东西连到意义)、面孔识别 |
| 证据强度 | 较硬(存在与大致连接);语言功能上的作用相对次要 |
极端囊纤维系统(extreme capsule fiber system, ECFS)
| 项 | 内容 |
|---|---|
| 连接 | 额叶岛盖 / BA 45、47 ↔ 颞叶中后部 |
| 一般认为管什么 | 词汇-语义检索(在 Friederici 的框架里是第二条腹侧通路的主角) |
| 证据强度 | 存在较硬;它是"一片区域"而不是"一根束",把它当单条纤维束讲是过度简化 |
中纵束(middle longitudinal fasciculus, MdLF),这条要特别小心
| 项 | 内容 |
|---|---|
| 连接 | 说法很多:从颞上回 ↔ 角回(最初的猴研究),到颞上回 ↔ 顶上小叶/枕顶区(人类研究) |
| ⚠️ 存在性 | 争议很大。经典的(非追踪类)人类白质研究没有描述过它;一些纤维解剖研究未能证实它;支持它存在的主要是弥散追踪证据,后来部分解剖研究又给了正面结果。"它到底存不存在"这个问题本身还没有关闭。 |
| ⚠️ 分段 | 至少有两套互相冲突的方案:三段 vs 两段 |
| 一般认为管什么 | 这个也变了:早期被提为"优势半球的语言信息主通道",但术中电刺激没能在其前部诱发出语言障碍,加上它缺乏显著的左侧优势、角回终止点未能确立,近年有作者主张把它从"语言通路"改划到"听觉通路"(高级听觉加工、视听整合) |
| 证据强度 | 最弱的一条。存在性、分段、功能三项全都有争议 |
⭐ MdLF 是这一小节最好的教材:它展示了"白质通路的语言功能"
这类结论有多脆弱,一条束可以从"语言主通道"变成"听觉通路",
而中间没有新的病人、没有新的实验,只是证据标准提高了。
你以后看到"某条白质束支撑语言"这种句子,先问:是哪种方法测的?有临床对照吗?
额斜束(frontal aslant tract, FAT),顺带提一条非经典的
| 项 | 内容 |
|---|---|
| 连接 | 辅助运动区(SMA/pre-SMA)↔ 额下回(岛盖部) |
| 一般认为管什么 | 言语流畅性(启动和维持言语输出);与口吃有关联;近年也被联系到句法 |
| 证据强度 | 存在较硬(追踪+解剖);功能与流畅性的关联有临床支持,但"和口吃的因果关系"仍在研究中,不宜写成定论 |
7.3.3 一张速查表
| 通路 | 位置 | 主要连接 | 一般认为管什么 | 证据强度 |
|---|---|---|---|---|
| AF | 背侧 | IFG ↔ 后 STG | 复杂句法、复述 | 较硬(临床支持强) |
| SLF(II/III) | 背侧 | 额 ↔ 顶 | 感觉-运动映射 | 连接较硬,偏侧化有争议 |
| IFOF | 腹侧 | 枕 ↔ 眶额/额极 | 语义 | 存在性有争议 |
| UF | 腹侧 | 前颞 ↔ 眶额 | 语义/情景记忆 | 存在较硬,功能较软 |
| ILF | 腹侧 | 枕 ↔ 前颞 | 视觉-语义映射 | 较硬 |
| ECFS | 腹侧 | 额岛盖 ↔ 颞中后部 | 词汇-语义检索 | 存在较硬(但是"片"不是"束") |
| MdLF | 腹侧(?) | 颞上回 ↔(说法不一) | 从"语言"改判为"听觉" | 三项全有争议 |
| FAT | 背侧(额内) | SMA ↔ IFG | 言语流畅性 | 存在较硬,功能部分支持 |
⚠️ 这张表的使用说明:"较硬"不等于"确定"。
上表所有"较硬"的条目,指的是该束的解剖存在性有多个独立方法支持;
"功能"那一列一律应当加上"一般认为"四个字,
因为"某条白质束管某个功能"这类结论,本质上仍然是相关性的
(损伤研究也是相关:你不能随机把一个人的弓状束切掉)。
要谈因果,需要术中电刺激或损伤-症状的双分离设计(回到《认知神经科学核心》§6 误解三)。
7.4 边界与批评
- dMRI 追踪的"假阳性"是系统性的:纤维靠近皮层时各向异性下降,
追踪算法容易停在错误的终点;体素内交叉纤维会让追踪"拐弯"。
所有基于 dMRI 的通路图,都应该被当成"解剖假说",而不是"解剖事实"。 - "束 = 功能"是一个不成立的等式:一条纤维束只是物理连接,
它的功能取决于它两端连接的是什么、以及什么条件下被激活。
"弓状束损伤 → 复述困难"是可靠的;"弓状束 = 复述中枢"是不成立的。 - 个体差异极大:白质通路的走行和终止点在不同人之间差异显著,
有些追踪研究报告的个体间重叠率只有 40%–90%
(Forkel et al. 2014 报告 iFOF 的束核个体间重叠在这个范围内)。
所以"标准解剖图"本身就是一种平均化的虚构。
现代语言神经科学的主语,已经从"区"换成了"网络 + 通路";
但每一条通路的功能归属,都比教科书的语气所暗示的要软得多。
8 语言与人脑(二):双语与脑,以及"双语优势"这个说法
为什么这门课要单列一节讲双语? 三个理由:
- 北语的语境:这是一所语言类大学,绝大多数学生(包括你)是双语者或多语者,
"双语对脑有什么影响"是这门课里和你个人最相关的一节。 - 科学上:双语是研究"经验如何塑造脑"的自然实验,
在同一个物种里,有一部分个体长期处于一种特殊的认知需求下。 - ⚠️ 而且它是最好的"科学自我修正"教学案例:
一个在 2000 年代被大量报道、进入科普与政策话语的结论,
在 2010 年代被一系列元分析和重复研究大幅削弱。
这一节真正要讲的,是一个科学结论怎么被推翻,"双语有没有优势"是这件事的案例。
8.1 两个语言在脑里怎么放
先问一个基础问题:一个会中英双语的人,两套语言是分开存还是重叠存?
主流答案:大面积重叠,但不是完全重合。具体地说:
- 成年后学习第二语言的人,两种语言在左额-颞语言网络内大量重叠,
同一个"读句子"的定位器,在中英文上都会点亮大致相同的一片区域。 - 重叠的程度随熟练度和习得年龄变化:熟练度越高,重叠越多;
低熟练度者加工 L2 时,常常招募更多区域和更强的激活,
这里的解释落在"L2 更难,需要更多资源",而不在"L2 在别的地方"
(回到《认知神经科学核心》§6 误解一:激活更强可能只是任务更难)。 - ⚠️ 一个必须点破的混淆:早期不少研究报告"L2 激活了不同的区域",
但没有匹配难度,L2 任务对被测者来说本来就比 L1 难。
难度一匹配上,很多差异就消失了。这与 §8.2 要讲的"多需求系统混淆"是同一类问题。
所以"两种语言在脑里分开存"这个说法,对成人双语者基本不成立。
(对早期同步习得的双语者,一些研究报告了更细的差异,
例如两个语言在左额下回内有部分不重叠的子区。
⚠️ 这类结果的效应大小和可重复性仍在讨论中,本页不写成定论。)
那你拿什么区分"现在说的是哪种语言"? 这就引出了下一小节。
8.2 语言控制:双语者为什么要多干一件事
单语者说话时,不需要决定"用哪种语言";双语者需要。
而且不只是"开口前选一次",两个语言的词汇是同时被激活的,
所以双语者必须持续抑制另一种语言。这带来了一个额外的认知任务:
语言控制(language control):在两种(或多种)语言之间选择、切换、抑制的机制。
神经上的一致发现是:语言控制不只是语言网络在干活,
它需要一组"域一般"(domain-general)的控制区域参与:
- 背侧前扣带(冲突监测)
- 左侧尾状核(语言选择与切换;双语失语症的证据很有力)
- 前额叶(尤其是左额下回和背侧区域)
- 顶叶下小叶(注意与工作记忆的参与)
这个框架由 Abutalebi 和 Green 提出并系统化
(Abutalebi, J., & Green, D. (2007). Bilingual language production: The neurocognition of
language representation and control. Journal of Neurolinguistics, 20(3), 242–275;
以及他们 2016 年在 Bilingualism: Language and Cognition 上的后续综述)。
⭐ 注意这一节的逻辑位置:"语言控制需要域一般区域"这一点,是理解
"双语优势"假说的关键。论证链条是:
双语者每天都在高强度使用这些域一般控制区域 →
用得多就练得强(像肌肉一样)→ 所以双语者的一般认知控制能力更好。
"双语优势"假说就建立在这条链上。下一小节检查这条链。
8.3 ⭐ "双语优势":一个被大幅削弱的说法
先把假说的原始形态说清楚,别打稻草人。
假说(2000 年代的主流叙事):因为双语者终身都在做语言控制
(选择、抑制、切换),这套练习会泛化到非语言的认知控制任务上,
使得双语者在抑制、切换、工作记忆、注意等方面优于单语者;
进一步的推论是双语可能延缓认知老化、降低痴呆风险。
早期支持它的关键研究:Bialystok 等的研究(例如 Bialystok, Craik, Klein & Viswanathan
(2004), Bilingualism, aging, and cognitive control: Evidence from the Simon task,
Psychology and Aging, 19(2), 290–303)报告了双语者在 Simon 任务上的优势。
这些研究在 2000–2015 年间被大量引用,进入了科普、媒体和政策文件。
然后是系统性的反转。以下是四类关键证据。
证据一:发表偏倚(publication bias),这个最致命。
de Bruin、Treccani 和 Della Sala (2015) 做了一件很聪明的事:
他们不看已发表的论文,而是看 1999–2012 年间 169 个会议上的 104 份会议摘要,
会议摘要是"几乎所有做过这项研究的人"都留下的痕迹,包括那些后来没发表的。
然后追踪哪些摘要最终变成了论文:
| 摘要的结论 | 最终被发表的比例 |
|---|---|
| 完全支持双语优势 | 最高(约 68%) |
| 混合支持 | 中间(约 50%) |
| 混合挑战 | 中间(约 39%) |
| 完全挑战(没找到优势) | 最低(约 29%) |
而且这个差异不能用样本量、统计功效或所用任务解释。
漏斗图检验也给出了不一致的证据。
(de Bruin, A., Treccani, B., & Della Sala, S. (2015). Cognitive advantage in bilingualism:
An example of publication bias? Psychological Science, 26(1), 99–107。
⚠️ 具体的百分比在不同报道里有出入(我看到 63%/36% 与 68%/29% 两个版本,
分母定义不同),引用时请以原文表格为准或标"约"。)
⭐ 这意味着什么? 文献库里流通的"双语优势"证据,是被一个偏向阳性结果的
过滤器筛过的。你读到的 meta 分析如果只纳入已发表文献,
它的效应量估计天生就是偏高的,哪怕分析方法完全正确。
证据二:元分析,校正之后,优势消失。
Lehtonen 等 (2018) 做了迄今最系统的一次元分析:
152 项成人研究、来自 27 个国家、891 个效应量,而且主动纳入了未发表数据。
| 阶段 | 结果 |
|---|---|
| 校正发表偏倚之前 | 抑制、切换、工作记忆上有一个非常小的双语优势;监测和注意上没有 |
| 校正发表偏倚之后 | 所有领域都没有证据支持双语优势 |
| 语言流畅性 | 双语者反而略差(可能是每种语言的使用暴露量较少所致) |
作者结论(大意):已有证据不支持"双语与成人认知控制功能优势相关"这一广泛持有的看法;
双语的好处在于语言技能和沟通,而不在于一般执行功能。
(Lehtonen, M., Soveri, A., Laine, A., Järvenpää, J., de Bruin, A., & Antfolk, J. (2018).
Is bilingualism associated with enhanced executive functioning in adults? A meta-analytic review.
Psychological Bulletin, 144(4), 394–425。
⚠️ 我核对到的是定性描述("very small" / "no evidence"),具体效应量的数值请以原文为准。)
证据三:大样本研究,优势小到没有实际意义。
Nichols 等 (2020) 用一个11,041 人的大样本(不是几十人的实验室样本),
测了 12 项执行功能任务:
- 在未匹配的组里,双语者只在 1 项任务上更好,而单语者在 4 项任务上更好;
- 把两组在混杂因素上匹配之后,所有差异都消失了;
- 即使不匹配,那个"双语优势"的效应量也小到对任何个人的认知表现都无关紧要。
(Nichols, E. S., Wild, C. J., Stojanoski, B., Battista, M. E., & Owen, A. M. (2020).
Bilingualism affords no general cognitive advantages: A population study of executive function
in 11,000 people. Psychological Science, 31(5), 548–567。)
证据四:批评者指出"阳性结果"有一个更简单的解释。
Paap 和 Greenberg (2013) 系统检查了报告双语优势的研究,主张
证据不一致、且阳性结果常常来自小样本、未预注册、以及分析灵活度过大的研究
(Paap, K. R., & Greenberg, Z. I. (2013). There is no coherent evidence for a bilingual
advantage in executive processing. Cognitive Psychology, 66(2), 232–258)。
一个关键的方法学细节:很多"双语优势"来自极端组比较
(把"纯单语者"和"高熟练双语者"对比),而两组的社会经济地位、移民背景、教育水平常常不同。
这些差异足以独立产生"认知优势",而不需要双语参与。
8.3.1 那么,"争议"现在是什么状态?
这一小节必须如实,不能写成"已经解决"。
| 立场 | 主张 | 代表 |
|---|---|---|
| 主流(削弱派) | 校正发表偏倚后,成人一般执行功能上的双语优势没有可靠证据;早期结果主要来自小样本、发表偏倚和混杂 | Lehtonen 2018;de Bruin 2015;Paap & Greenberg 2013;Nichols 2020 |
| 保留派 | 优势可能存在但很小、只在特定条件下显现(特定任务、特定人群、特定生活场景);用"整体 EF"这个粗概念去找它本身就方法不当 | Bialystok 及其合作者;也有作者主张应该看"双语经验的具体维度"而非"双语 vs 单语"的二分 |
| 转向 | 与其争论"有没有一般优势",不如研究双语经验如何具体地改变语言系统本身(这个效应是确定的) | 一批主张"放弃寻找优势、转向机制"的综述 |
⭐ 对这一节最重要的一句:
"双语者的一般认知优势"这个说法,在近年的大样本研究和校正发表偏倚的元分析中
被大幅削弱;目前没有可靠证据支持它成立。
但它也不是"已被证否",只是"没有足够证据支持",而这两者的区别,
恰恰是《实验方法论》反复强调的(见那页关于"零结果不等于证否"的讨论)。
8.3.2 那什么是确定的?把话说准
争议只发生在"泛化到非语言的一般认知"这一环上。以下几条是没有争议的:
- 双语者的语言系统本身显著不同:两套语言共享左额-颞网络、
需要持续的抑制和切换,这是可重复的、有神经证据的。 - 双语者在"语言相关"任务上的表现确实和单语者不同(比如词汇量在每种语言内更小、
但语言控制的灵活性更高)。这是"语言内的差异",不是"认知优势"。 - 语言控制招募域一般区域(§7.2),这一点也没有被推翻。
被推翻的是"招募 → 变强 → 泛化"这条更长的链。
所以准确的写法是:
❌ "双语能提升认知能力 / 延缓老年痴呆。"(过度外推,证据不支持)
✅ "双语者需要终身进行语言控制,这依赖一组域一般的控制区域;
但这套额外的需求是否带来可迁移到非语言任务的一般认知优势,
目前的大样本证据不支持,早期阳性结果很大程度上可由发表偏倚和组间混杂解释。"
注意第二句的长度是第一句的五倍。多出来的每一个字都在限定适用范围,
这和《语言认知神经科学》§5 追查"95% 在左脑"那个数字时的教训是同一个。
8.4 边界与批评
- ⚠️ 这一节的证据有它的边界:上面的元分析和大样本研究主要针对成人。
儿童双语者的证据更混杂,而"双语经验改变脑结构/功能"这类结论
(例如训练研究、纵向研究)和"一般认知优势"是两个不同的问题,
不要把前者的证据挪去支持后者。 - ⚠️ "双语"是一个极粗的变量:同时习得 vs 先后习得、高熟练 vs 低熟练、
两种语言的社会地位、使用场景(家庭/学校/工作)、代码切换的频率,
这些维度可能比"是/否双语"重要得多。
把它们压成一个二值变量,很可能把真实存在的细分效应平均掉了。
这既削弱了"有优势"的证据,也削弱了"没优势"的结论的推广性,
两边的推论都要小心。 - ⚠️ 出版生态的影响:这个领域同时受到"阳性结果好发"和
"推翻阳性结果也好发"两种偏倚的夹击。读任何一篇综述,先看它的纳入标准。
"双语优势"不是一个已经被证否的假说,
而是一个在更好的证据标准下失去了支持的假说。
这两句话的区别,就是这门课想教给你的科学态度。
9 语言与人脑(三):方法上的关键限制
9.1 第一层限制:fMRI 相关 ≠ 因果(这一层你已经在别处学过了)
《认知神经科学核心》§6 那三个误解,是这一节的地基,这里只做一件事:
把它们翻译成"语言研究"的版本,因为语言研究有几个特别容易踩的地方。
| 那页的误解 | 在语言研究里的具体样子 |
|---|---|
| 一:脑区亮了 ≠ 该区负责该功能 | "读句子时布洛卡区激活"→ 不能说"布洛卡区负责理解句子"。它可能只是在做工作记忆(句子比词串长,需要保持更多信息) |
| 二:功能分布 ≠ 定位无意义 | 语言确实依赖分布式网络,但损伤一个节点(如弓状束)确实会造成特定缺陷,分布不等于没有关键节点 |
| 三:神经证据 ≠ 心理学结论的证明 | "语言网络和一般认知网络重叠"→ 不能推出"语言不是模块"。这是一个实现层的观察,推不出计算层的结论 |
语言研究独有的两个坑:
- 任务的难度天然混淆:句子加工几乎总比词加工难。所以"句子 > 词"的激活差异里,
有多少是"语言结构",有多少是"更难"?这是 §8.2 的主题。 - "语言任务"这个说法太笼统:读句子、听故事、判断语法、命名图片,
这些任务激活的区域只有部分重叠。很多早期文献的分歧,就是因为大家做的任务不一样还不自觉
(这一点在《语言认知神经科学》§6 的"任务效应"提醒里出现过)。
9.2 ⭐ 第二层限制:语言网络 vs "多需求系统"
这一小节是"语言与人脑"这门课在方法论上最值钱的部分。
先介绍对手是谁:多需求系统(multiple-demand system, MD),
一组位于额叶和顶叶的区域,它们的特点是
对"任何困难的、需要注意的任务"都反应,不管这个任务是不是语言的:
做数学、做空间推理、做工作记忆、听被噪声掩蔽的句子,它都亮。
(系统的提出:Duncan, J. (2010). The multiple-demand (MD) system of the primate brain:
mental programs for intelligent behaviour. Trends in Cognitive Sciences, 14(4), 172–179。)
于是出现了一个直接的冲突:
旧文献说:布洛卡区(左额下回)在语言任务里激活 → 它是语言区
新发现说:布洛卡区也在一堆非语言难任务里激活 → 它凭什么算语言区?
这个问题有两种回答,而两种回答都有真实的、可引用的证据支撑。
把两边都摆出来,是这一节的全部任务。
9.2.1 支持"重叠"的证据:确实有
- 同一片皮层里,语言选择和域一般的子区混在一起。
Fedorenko, Duncan & Kanwisher (2012) 用逐被试功能定位器发现:
左额下回(布洛卡区)内部同时包含"只对语言反应"的小区和"对一般难任务反应"的小区,
它们相邻但可分离(Current Biology, 22(21), 2059–2062)。 - 额顶皮层存在大量"域一般"区域:
Fedorenko, Duncan & Kanwisher (2013, PNAS, 110(41), 16616–16621)
报告额叶和顶叶的局部区域对多种不同任务都反应。 - 很多经典"语言激活"的对照条件选得不好:
如果对照是"静息"或"看十字",那么"激活"里混着注意、努力、警觉的成分,
这部分激活和语言无关(回到《认知神经科学核心》§6 误解一那条实操建议)。
9.2.2 支持"分离"的证据:也有,而且很强
- 语言区对非语言任务基本不反应。 Fedorenko, Behr & Kanwisher (2011, PNAS,
108(39), 16428–16433) 的做法是逐被试定位语言区,然后给被试做
算术、空间/词语工作记忆、认知控制(Stroop、MSIT)和音乐任务,
每个非语言任务都特意设计了"难条件 vs 匹配的易条件"的对照。
结果:语言区对这些非语言任务几乎不反应,
即使这些任务在附近的区域引起了强烈激活。
这是"分离"的最强证据之一,
因为如果语言区只是"对难度反应",它在难条件的非语言任务里就该亮,但它没有。 - 两个系统的自发波动几乎不相关:Blank, Kanwisher & Fedorenko (2014,
Journal of Neurophysiology, 112(5), 1105–1118) 在静息和听故事两种状态下,
测量各区域 BOLD 信号自发波动的相关性:
语言系统内部高度相关,MD 系统内部高度相关,
而两个系统之间弱相关甚至负相关;数据驱动的聚类稳定地分出两个簇。
两套系统在功能上各自成一体、彼此分离。 - ⚠️ 而且这个发现有一个"元"层面的重要含义(Fedorenko 团队反复强调的方法论点):
过去很多"重叠"的结论,可能来自"跨被试平均"这个操作。
不同人的语言区在解剖上的位置有差异,把它们平均到一起,
相邻但不重叠的区域就会被抹成一片,看起来"重叠了"。
逐被试定位(functional localizer)之后,重叠常常消失。
9.2.3 用代码把"分辨率决定结论"这件事演出来
⚠️ 下面是模拟数据,目的是把"跨被试平均 / 分区粗糙"这个机制放大到看得见。
真实研究里的机制是"被试间解剖变异 + 群组平均",
下面的模拟用的是"分区大小",两者是同一类问题的不同版本,
我在最后的解读里会明确区分这两者,不要把模拟当成真实数据。
import numpy as np
rng = np.random.default_rng(5)
# ==================================================================
# 一个模拟的"左额下回(布洛卡区)":里面混着两类体素
# 类型 L:只对语言任务反应(语言选择性)
# 类型 M:只对"难任务"反应(多需求系统 MD)
# 两个任务:① 读句子(语言) ② 硬空间工作记忆(域一般、很难)
# 问:这个"脑区"看起来是不是"语言特异的"?答案取决于你把它切多细。
# ==================================================================
G = 60
is_lang = np.zeros((G, G), bool)
for cy, cx in [(14, 16), (18, 40), (40, 22), (36, 46), (28, 30)]:
yy, xx = np.mgrid[0:G, 0:G]
is_lang |= ((yy-cy)**2 + (xx-cx)**2) < 8**2
is_md = ~is_lang & (rng.random((G, G)) < 0.35) # MD 体素散布在其余地方
print("模拟一个 %d×%d 的'布洛卡区':语言体素 %d 个,MD 体素 %d 个"
% (G, G, is_lang.sum(), is_md.sum()))
print("(真实研究里的量级:Fedorenko 组在左额下回里找到的语言选择性和域一般子区,")
print(" 空间上是相邻但可分离的两小片。)")
print()
# 两个任务在这些体素上引起的"激活"
act_lang_task = is_lang.astype(float) # 读句子:语言体素亮
act_hard_task = is_md.astype(float) # 硬任务:MD 体素亮
def selectivity(k):
"""把 k×k 体素合成一个脑区,返回每个脑区的选择性指数"""
s = G // k
def block_mean(a):
return a[:s*k, :s*k].reshape(s, k, s, k).mean(axis=(1, 3))
rl, rm = block_mean(act_lang_task), block_mean(act_hard_task)
keep = (rl + rm) > 0 # 只看至少有点反应的脑区
sel = (rl[keep] - rm[keep]) / (rl[keep] + rm[keep]) # +1=纯语言, -1=纯MD, 0=没选择性
return sel, rl[keep], rm[keep]
print("=" * 76)
print("不同脑区大小下,同一个布洛卡区看起来是什么样")
print("=" * 76)
print(" 脑区边长 脑区数 平均选择性 |选择性|>0.8 的比例 '看起来像语言区'的比例")
for k in (1, 2, 3, 5, 10, 20, 60):
sel, rl, rm = selectivity(k)
frac_strong = float((np.abs(sel) > 0.8).mean())
frac_lang = float((sel > 0.8).mean())
print(" %2d×%-3d %5d %+.3f %.1f%% %.1f%%"
% (k, k, len(sel), sel.mean(), 100*frac_strong, 100*frac_lang))
print()
print(" ⭐ 单个体素(1×1)时,选择性指数是 ±1,每块都'非常特异'——")
print(" 你会得出结论:语言和一般认知在这是分开的两套东西。")
print(" ⭐ 把整块(60×60)当成一个'布洛卡区'时,选择性指数掉到 %.2f,"
% selectivity(60)[0][0])
print(" 语言任务和难任务都能让它'亮'——你会得出结论:布洛卡区是通用的,不特异。")
print()
print(" ⭐ 同一份数据,同一个脑区,两个相反的结论。差别只在'一个脑区算多大'。")
print(" 而一个脑区算多大不是数据给的,是研究者的先验假设——")
print(" 旧研究用粗分区,于是'布洛卡区什么任务都亮';")
print(" 新研究用逐被试的功能定位器,于是'语言和 MD 是相邻但分离的两片'。")
实跑输出
模拟一个 60×60 的'布洛卡区':语言体素 949 个,MD 体素 950 个
(真实研究里的量级:Fedorenko 组在左额下回里找到的语言选择性和域一般子区,
空间上是相邻但可分离的两小片。)
============================================================================
不同脑区大小下,同一个布洛卡区看起来是什么样
============================================================================
脑区边长 脑区数 平均选择性 |选择性|>0.8 的比例 '看起来像语言区'的比例
1×1 1899 -0.001 100.0% 50.0%
2×2 792 -0.357 95.1% 29.3%
3×3 395 -0.416 90.1% 23.3%
5×5 144 -0.371 77.8% 18.1%
10×10 36 -0.288 55.6% 11.1%
20×20 9 -0.099 0.0% 0.0%
60×60 1 -0.001 0.0% 0.0%
⭐ 单个体素(1×1)时,选择性指数是 ±1,每块都'非常特异'——
你会得出结论:语言和一般认知在这是分开的两套东西。
⭐ 把整块(60×60)当成一个'布洛卡区'时,选择性指数掉到 -0.00,
语言任务和难任务都能让它'亮'——你会得出结论:布洛卡区是通用的,不特异。
⭐ 同一份数据,同一个脑区,两个相反的结论。差别只在'一个脑区算多大'。
而一个脑区算多大不是数据给的,是研究者的先验假设——
旧研究用粗分区,于是'布洛卡区什么任务都亮';
新研究用逐被试的功能定位器,于是'语言和 MD 是相邻但分离的两片'。
把这张表读成三个阶段:
体素级(1×1) 选择性指数 = ±1,100% 的单元"非常特异"
│ 结论:语言和一般认知在这是分开的
▼
中间尺度(2×2 ~ 10×10) |选择性|>0.8 的比例从 95% 掉到 56%
│ 结论:变得模糊,取决于你切在哪
▼
整块级(20×20 以上) 强选择性比例 = 0%,平均选择性 ≈ 0
结论:布洛卡区是"通用的",什么任务都亮
⚠️ 三点必须说清楚,否则这个模拟会误导你:
- 这是模拟数据,"体素"是假的。它演示的是一个逻辑:
只要两类功能单元在空间上交错,"把它们平均起来"就会抹掉选择性。
真实的机制是跨被试平均 + 解剖变异,不是"分区大小",
但两者在数学上是同一个操作:对空间上交错的东西做平均。 - "选择性指数"这个量是我为了演示定义的,不是标准指标。
真实研究里用的是对比估计值(contrast estimate)和统计检验,
而不是这样一个 +1/−1 的比值。别把这个指数当成文献里的东西引用。 - 模拟里两类体素是 50:50 混合的,这是为了把效应做大、做明显。
真实比例我不知道,而且这个比例决定了"平均之后还剩多少选择性",
本页没有声称知道真实比例。如果你要引用真实数字,去看 Fedorenko 组的原始论文。
9.2.4 这个争议该怎么收场?
诚实的答案是:没有收场,但争点已经变了。
| 旧的争点(1990s–2000s) | 新的争点(2010s–) |
|---|---|
| "语言是模块的,还是和一般认知共用的?" | "在什么尺度上分离,在什么尺度上重叠?" |
| 用粗分区回答 | 用逐被试功能定位回答 |
| 结论:布洛卡区什么任务都亮 → 语言不模块 | 结论:左额下回内部有可分离的语言选择性子区,且语言系统与 MD 系统整体上功能分离(Blank et al. 2014 的波动相关证据) |
| 但:这个结论依赖"功能定位器能干净地划出语言区"这个前提 | 而:定位器本身也是一种假设驱动的方法,它对语言区的定义会反过来影响结果 |
⭐ §8.2 不打算回答"语言到底是不是模块",它要教给你的是这两件事:
① "两个网络重叠"和"两个网络分离"可以同时是同一份脑数据上的真命题,
取决于你用什么尺度去看。
② 而"用什么尺度"是一个先验决定,不是一个数据决定。
这和 §3.5 那个"52 次 vs 17 次"是同一个道理:
数据给的是一个"区域",你在区域里选哪个点,靠的是数据之外的东西。
9.3 第三层限制:这张清单
把语言与人脑这门课的方法学限制列成一张表(这张表是这一节的纲要):
| 限制 | 具体表现 | 本页哪节 |
|---|---|---|
| 相关 ≠ 因果 | 激活只说明"参与",不说明"必需";要因果需要 TMS 或损伤 | §8.1 |
| 反向推理 | 从"某区亮了"推"被试在做 X",漏掉先验和特异性 | §8.1(详见《认知神经科学核心》§6) |
| 任务难度混淆 | 语言任务几乎总比对照难,"语言激活"里混着"努力" | §8.2.1 |
| 分辨率/平均 | 粗尺度看是重叠,细尺度看是分离 | §8.2.3 |
| dMRI 追踪的偏差 | 终点不准、交叉纤维导致错误追踪 | §6.3 |
| 个体差异 | 通路走行和终止点的个体间重叠可低到 40% | §6.4 |
| 小样本 + 分析灵活度 | 脑成像研究的可重复性危机 | 《认知神经科学核心》§6 |
| 任务效应 | 换一个任务,"语言区"就不一样 | §8.1 |
"哪里亮了"从来不是一个可以单独成立的结论;
它永远需要"相对于什么、在多大尺度上、在谁身上"这三个限定。
10 合流:同一个箭头,两种失效方式(全篇落点)
到这里两半都走完了。这一节把它们接起来,这是导论⓪那个承诺的兑现。
10.1 把两条链并排铺开
学习分析 语言与人脑
──────── ──────────
心理状态:会不会 心理状态:语言加工在哪、何时
▲ ▲
│ ① 假设:行为反映学习 │ ① 假设:激活反映加工
│ (含 P(G)、P(S) 两个含噪通道) │ (含"纯插入"和"难度不混淆")
│ │
信号:答对/答错 信号:BOLD / ERP
▲ ▲
│ ② 假设:这道题只考这一个技能 │ ② 假设:这个定位器干净地划出了语言区
│ │
原始数据:LMS 日志 原始数据:体素时间序列
▲ ▲
│ ③ 假设:点击 = 投入(构念效度) │ ③ 假设:粗分区/平均不掩盖子结构
│ │
事件:鼠标点了 事件:机器扫了一圈
⭐ 两条链的每一层都有一个假设,而每一层的假设都可以独立地破。
这个并排结构让两件事变得非常清楚:
(一)两门课的失效方式不同,但失效的位置相同。
| 失效方式 | 具体样子 | |
|---|---|---|
| 学习分析 | 标签是含噪的代理变量 | 答对里有 9% 是猜的;点击里有大量"卡了/误触";"用时"对设备敏感 |
| 语言与人脑 | 观测是多义的 | 一个激活可以对应很多心理过程(反向推理);一个"区"在不同分辨率下是两种东西 |
前者的问题是"信号本身脏",后者的问题是"信号到心理状态的映射是一对多"。
但两者都发生在同一个箭头上:从看得见的,跨到看不见的。
(二)两门课对"指标"的态度是同一个教训。
- 学习分析里:AUC 0.77 的模型在两个不同的世界(T=0.05 / T=0.15)里表现一样,
但给出的教学建议差三倍(52 次 vs 17 次)。 - 神经科学里:同一份脑数据,在体素尺度上"完全分离",
在粗分区尺度上"完全重叠"。
同一个模式:指标(AUC / 分辨率 / 选择性指数)把多维的现实压成一维,
而压的方式是研究者选的。
这就是《实验方法论》里"指标决定结论"那句话在两个领域的具体形态。
10.2 三个可以随身带走的判断
判断一:问"这一步依赖什么假设",而不是问"这个结论对不对"。
任何"数据表明 X"的句子,都可以被拆成三段:
信号 → (假设)→ 心理状态 → (另外的假设)→ 行动建议。
"对不对"这个问题只能问第一段;后两段该问的是"假设成立吗"。
判断二:区分"没有证据"和"证据表明没有"。
- 双语优势:校正发表偏倚后没有证据支持(§7.3)。
这不等于"已被证否"。 - MdLF 的语言功能:证据不足以支持,近年有作者主张改判为听觉通路(§6.3.2)。
这不等于"确定是听觉通路"。 - BKT 的参数:数据不足以唯一确定(§3.5)。这不等于"参数没有意义"。
这三个"不足以"是同一个认识论状态的三个实例。
它们在写作上的正确表达都是"目前证据不支持",而不是"已被推翻"。
判断三:警惕"把模型输出当成世界真相"的那一步。
- 学习分析里,这一步是"模型说 82%,所以这个学生就是高风险",
§5.1 那个自我实现的循环就发生在这里。 - 神经科学里,这一步是"这个区亮了,所以他刚才在做语义加工",
《认知神经科学核心》§6 的反向推理就发生在这里。
这两步在语法上都很顺、在日常推理里命中率都不低、在科学论证里都不成立。
这就是为什么它们这么难避免。
10.3 反过来:为什么"有假设"不是坏事
这一页花了大量篇幅讲"假设会破",但不要得出"那什么都不可信"这个结论。
那是错的,而且错得有害。
⭐ 正确的态度是:假设不是缺陷,假设是全部信息的来源。
没有假设,信号就是纯粹的噪声,"答对"和"脑区亮了"本身没有任何含义。
是"行为反映学习"这条假设,让"答对"变成了关于学习的证据;
是"激活反映加工"这条假设,让 BOLD 变成了关于认知的证据。所以问题从来都是"假设写清楚了没有、被检验过了没有",而不是"要不要假设"。
具体到做法上,两门课给的是同一套作业:
| 做法 | 学习分析里的样子 | 语言与人脑里的样子 |
|---|---|---|
| 把假设写进模型 | BKT 明确写出 P(G)、P(S)(而不是假装数据干净) | 用"难 vs 易匹配"的对照(而不是静息) |
| 检验假设 | 参数恢复实验(§3.5) | 逐被试定位 + 双分离设计 |
| 报告不确定性 | 报告参数的置信区间,不只报点估计 | 报告体素级/被试级变异,不只报群组平均图 |
| 给出反例条件 | 说明模型在什么数据上会失效 | 说明结论在什么任务/人群上不成立 |
§9:两门课都是"从间接信号反推认知";反推永远依赖假设;
所以这一页真正的技能,是"把假设找出来、说出来、检验它"。
11 和你专业的关系:智能导学系统与自适应学习
这一节回答一个很实际的问题:学了这一页,你能去做什么?
最直接的答案就是智能导学系统(Intelligent Tutoring System, ITS),
它是学习分析、知识追踪和认知科学三者的交汇点,也是本专业最对口的一类工作。
11.1 ITS 是什么,以及它和 BKT 的血缘
ITS 的定义很朴素:一个能在学生做题的每一步给出反馈、并根据学生的状态决定下一步给什么题的计算机系统。
它和 BKT 的这层关系,是"从同一个实验室长出来的",不靠"用了同一个方法":
Anderson 的 ACT-R 认知理论(1993)
│
├──► BKT(Corbett & Anderson 1995)—— 把"会不会"变成可推断的隐状态
│
└──► Cognitive Tutor(卡内基梅隆的代数/几何辅导系统)
—— BKT 的"原生应用":用 P(掌握) 决定什么时候推进到下一个技能
这个血缘很重要,因为它解释了 ITS 的一个特点:
ITS 的"智能"主要来自一个认知模型(哪一步需要哪个技能),
而不是来自通用机器学习。也就是说,
ITS 是把"人怎么学"的理论编码进软件,而不是"让数据自己说话"。
一个 ITS 的循环(每一轮都是本页内容的实例):
出题 ──► 学生作答 ──► 判定对错 ──► 更新知识估计 ──► 决定下一步
▲ (信号) (§3 知识追踪) (决策)
│ │
└──────────────────────────────────────────┘
决定依据:知识估计 + 教学策略
⚠️ 这里有一个本页反复出现的危险,在 ITS 里变成了现实:
"决定下一步"这一步,会把 §3.5 那个"参数不确定"直接变成"教学行动",
如果参数估计偏了(52 次 vs 17 次),系统就会真的给学生多排 35 道题(或少排 35 道题)。
模型的假设,在 ITS 里会变成学生的现实。
11.2 效果到底多大?一个"看你怎么算"的教科书案例
ITS 的效果是教育技术领域被研究得最多的问题之一,而它的答案非常不统一。
这个不统一本身就是这一页最好的例子。
| 综述 | 范围 | 报告的效应量 |
|---|---|---|
| VanLehn (2011),Educational Psychologist 46(4):197–221 | 人类辅导 vs 各类计算机辅导 | 步进式 ITS $d \approx 0.76$;人类辅导 $d \approx 0.79$ |
| Kulik & Fletcher (2016),Review of Educational Research 86(1):42–78 | 50 项对照评价 | 中位数 $d = 0.66$ |
| Steenbergen-Hu & Cooper (2013),Journal of Educational Psychology 105(4):970–987 | K-12 数学,26 篇报告 / 34 个独立样本 | $g = 0.01 \sim 0.09$(几乎为零) |
把这三个数字并排放:0.01、0.66、0.76。
同一个技术,不同综述给出的效应量差了两个数量级。
⚠️ 而且它们之间的差异来自三个真实的、可解释的因素,跟"谁算错了"无关:
- 对照组是什么。"相对于无辅导"和"相对于常规课堂教学"是两个完全不同的问题。
VanLehn 的分母是"没有辅导的同一内容教学",Steenbergen-Hu & Cooper 的分母是
常规教师教学,后者难赢得多。 - 测验是什么。 Kulik & Fletcher 特别指出效应量高度依赖测验类型:
用本地自编测验时效应大得多,用标准化测验时小得多
(我看到的具体数值是 0.73 vs 0.13,来自对该综述的转述,
引用前请核对原文表格)。
这个差异说明了一件很不舒服的事:ITS 可能确实教会了它自己出的题,
但没有迁移到标准化测量上。 - 研究对象和时长。 Steenbergen-Hu & Cooper 发现:
干预短于一学年时效应更大;而且 ITS 对普通学生比对低成就学生更有效。
⭐ 第 3 条的最后半句值得单独拉出来:
"ITS 对低成就学生的帮助更小",这意味着如果无差别地推广 ITS,
它可能扩大而不是缩小成绩差距。
原文的解释是:低成就学生更容易在卡住时放弃、更容易出操作性错误、
更需要老师的引导。这是一个纯粹的教育伦理问题,而且它无法用"技术更强"来解决。这条也直接呼应 §5:一个教育技术对谁有效、对谁无效,
是它是否该被推广的核心问题,而这个问题在采购演示里从来不会被问。
还有一条必须说的:一些独立的评价机构
(如美国的 What Works Clearinghouse,以及 Slavin 等的综述)
在若干 Cognitive Tutor 的评价里报告了接近零或没有改善的结果。
也就是说,连"ITS 的旗舰产品"都没能稳定地复现出正的效应量。
11.3 自适应学习:现状与批评
"自适应学习"是 ITS 的商业化名字。它和 ITS 的技术内核基本一致
(知识追踪 + 内容推荐),但宣传语言不同。以下是几条必须知道的批评:
批评一:把"适配难度"当成"个性化"。
真正有证据支持的教学干预,是反馈、间隔、检索练习、解释,
这些是教学策略层面的东西。
而多数"自适应"系统做的只是"调整题目难度",
这是一个排序问题,不是一个教学问题。
"把题调到刚好他不会做的难度"本身不教任何东西。
批评二:数据的闭环只覆盖"可测量的部分"。
系统能看到对错和点击,看不到:
学生为什么错(概念误解?计算失误?没读题?)、理解得多深、会不会迁移。
于是系统优化的一定是它能测的那部分,
这会让教学向"系统能测的东西"偏移(这就是 §4.3 理由四的古德哈特定律)。
批评三:它把教师从"设计的中心"推到了"使用的边缘"。
很多系统的实施模型假设"老师会看仪表盘并据此调整教学"。
但真实课堂里,老师的时间已经被占满了,
而且系统给的"洞察"往往是老师早就知道的事
("这个学生最近不活跃",老师上周就发现了)。
这是 §2.2 那个"仪表盘不等于决策"的现实版本。
批评四:算法的可申诉性。
如果一个自适应系统决定"这个学生现在不该学分数",
谁能解释为什么?谁能推翻它?(§5.2 议题二)
11.4 一个诚实的现状总结(以及大模型时代)
| 结论 | 证据强度 |
|---|---|
| ITS 在特定条件下(步进式、结构良好的学科、短于一学年)能产生中等正效应 | 较硬(多项元分析一致) |
| ITS 相对于常规教师教学的优势远小于宣传(可能接近零) | 中等(取决于综述与学科) |
| ITS 对低成就学生的帮助小于普通学生 | 中等(一项元分析报告,且后来的元分析没有复现这个差异,见下) |
| ITS 改善的往往是自编测验成绩,标准化测验上效应很小 | 中等(由综述的调节效应分析支持) |
| "自适应"本身(而不是具体的教学策略)带来学习增益 | 证据薄弱,这是最该被质疑却最少被质疑的一条 |
⚠️ 关于"对低成就学生帮助更小"这一条要特别注意:
Steenbergen-Hu & Cooper 报告了"普通学生受益更多",
但后来的一项元分析(2025 年的 arXiv 预印本)发现两类学生的效应量接近,
没有复现这个差异,所以这一条也处在"有争议"的状态。
(⚠️ 那个 2025 年的工作是预印本,我无法确认它是否已经过同行评议,引用时请注明"预印本"。)
关于大模型时代的 ITS:生成式模型(GPT 系列等)让"自然语言辅导对话"
变得可能,这在 2020 年之前是 ITS 最难做的部分(当时只能做按钮和选项)。
但这一页的所有批评一条都没有消失:
- 知识追踪的参数不确定性没有消失(换成大模型只是换了一套更不可解释的参数);
- 预测-干预悖论没有消失;
- 低基准率下的指标骗局没有消失;
- 幻觉(hallucination)是新加的:一个会自信地讲错知识点的辅导系统,
比一个只会推题的旧式 ITS 更危险。
⭐ §10:"技术能做什么"和"技术上做得对不对"是两个问题;
而在教育里,还有一个更硬的问题:"它对这个学生有帮助吗?"
前两个问题有答案,第三个问题的答案,好得出乎意料地少。
12 习题(带答案)
先自己写,再对答案。前 6 题是学习分析侧、后 4 题是语言与人脑侧,
第 10 题是两边的综合题,也是这一页真正想考的东西。
带 ★ 的是基础题,★★★ 的需要你自己动笔推导或设计。
⚠️ 所有需要计算的题,答案我都是用 §3–§4 里那套代码实际跑过一遍才写下来的;
需要核对的地方,我把关键输出直接贴在答案里。你也可以自己跑一遍对照。
12.1 第 1 题(BKT 一次更新)★
四个参数 $P(L_0)=0.5$、$P(T)=0.2$、$P(G)=0.25$、$P(S)=0.1$,
学生做第一道题时答错了。求:(a) 作答后的后验 $P(L)$;(b) 下一题之前的 $P(L)$;
(c) 和 §3.3 的例子($P(L_0)=0.3$,答错后 0.0508)相比,为什么这次的后验更高?
答案
(a) 分子 $= P(L_0)\cdot P(S) = 0.5 \times 0.1 = 0.05$。
分母 $= 0.05 + (1-0.5)\times(1-0.25) = 0.05 + 0.375 = 0.425$。
后验 $= 0.05 / 0.425 = \mathbf{0.1176}$。
(b) $0.1176 + (1-0.1176)\times 0.2 = 0.1176 + 0.1765 = \mathbf{0.2941}$。
(c) 先算清楚两个例子的分子分母,再解释。后验 $= \dfrac{pS}{pS + (1-p)(1-G)}$:
| $p$ | $S$ | $G$ | 分子 $pS$ | 分母 | 后验 | |
|---|---|---|---|---|---|---|
| §3.3 例 | 0.30 | 0.10 | 0.20 | 0.0300 | 0.5900 | 0.0508 |
| 本题 | 0.50 | 0.10 | 0.25 | 0.0500 | 0.4250 | 0.1176 |
分子 +66.7%,分母 −28.0%,合起来后验变成 2.3 倍。两个变化各有来源:
- 分子变大:$p$ 从 0.3 涨到 0.5(先验更强),
而"他会"这条路产生"答错"的概率 $S$ 没变,
所以"答错"这条证据在更强的先验基础上加成,绝对量更大。 - 分母反而变小(这是关键,也是最反直觉的一步):
分母是 $pS + (1-p)(1-G)$。$p$ 变大让第二项 $(1-p)(1-G)$ 大幅缩水
($0.7\times0.8=0.56 \to 0.5\times0.75=0.375$),
这个缩水幅度超过了第一项 $pS$ 的增长($0.03\to0.05$),净结果是变小。
直观解释:猜对率越高($G$ 更大),"不会"这个假设越难解释"答错"这件事
(因为不会的人本来应该更容易蒙对),所以"不会"那一支被压缩得更狠。
这就是"答错"这条证据的实际力度来源。
⚠️ 顺便清一个常见的算法错误:有些人会把分母写成 $1-P(C)$ 以为是另一套公式,
其实两者恒等:
$1 - P(C) = 1 - [p(1-S) + (1-p)G] = (1-p)(1-G) + pS$。
上面两种写法是同一个东西,可以自己代数验证。
12.2 第 2 题(BKT 的稳态)★★
一个学生永远答错(连续做 100 道题,全部答错)。
用 $P(T)=0.1$、$P(G)=0.2$、$P(S)=0.1$,
求 $P(L)$ 最终会稳定在哪个值。给出闭式解,并解释这个结果的奇怪之处。
答案
设稳态为 $p^*$。稳态满足:
$$p^* = \underbrace{\frac{p^* S}{p^* S + (1-p^*)(1-G)}}_{\text{后验}} (1-T) + T$$
把 $a = S$、$b = 1-G$ 代入并整理,得到关于 $p^*$ 的二次方程:
$$(1-G-S)\,{p^*}^2 + \bigl[S - (1-G)(1+T)\bigr] p^* + T(1-G) = 0$$
代入数值:$(1-0.2-0.1)p^2 + [0.1 - 0.8\times1.1]p + 0.1\times0.8 = 0$,
即 $0.7p^2 - 0.78p + 0.08 = 0$,也就是 $35p^2 - 39p + 4 = 0$。
$$p^* = \frac{39 \pm \sqrt{39^2 - 4\cdot35\cdot4}}{2\cdot35} = \frac{39\pm31}{70} \;\Rightarrow\; p^* = 1 \ \text{或}\ \frac{4}{35}$$
取非平凡解:$p^* = \dfrac{T(1-G)}{1-G-S} = \dfrac{0.1\times0.8}{0.7} = \dfrac{4}{35} \approx \mathbf{0.1143}$。
代码核对(用 §3.3 的 bkt_update 迭代,实跑输出):
永远答错时 P(L) 的稳态(从 0.9 出发迭代 60 次):0.1142857143
从 0.0001 出发迭代 200 次: 0.1142857143
解析解 T(1-G)/(1-G-S) = 0.100000 × 0.8 / 0.7 = 0.1142857143
闭式解与迭代一致: True
含义:即使连错两百次,模型仍认为他有 11.4% 的概率'其实会'——永远不会归零。
奇怪之处有三层:
- 永远答错,模型却永远不认为他"不会"。 $P(L)$ 有一个正的下界 $11.4\%$。
原因是那个 $T$ 项:每一道题都给了"他可能刚好在这一步学会了"一份概率。 - 这个下界可以被解析算出来,而且只依赖三个参数($T$、$G$、$S$,和 $P(L_0)$ 无关!)。
这意味着不管这个学生一开始被估计成什么样,最终都会收敛到同一个值,
BKT 是"遗忘先验"的。 - 如果 $1-G-S < 0$(即 $G+S>1$),那个二次方程的解会跑出 $[0,1]$。
这就是为什么 §3.5.2 的网格搜索里我加了一句if g + s >= 1.0: continue,
那个约束来自模型本身的要求($G+S<1$ 才有意义),不是图省事
(直观理解:如果"猜对率 + 失误率 $\ge 1$",观测就完全不能区分"会"和"不会"了)。
12.3 第 3 题(可辨识性)★★★
(a) 用一句话解释:为什么"两组参数的预测准确率几乎相同"不能推出"这两组参数等价"。
(b) §3.5.3 里 A、B 两个世界的测试 AUC 分别是 0.7646 和 0.7711。
如果只看这两个数字,你会选哪个模型?为什么这个选择是危险的?
(c) 设计一个(假想的)实验,能真正把 A 和 B 区分开。说明你需要什么样的数据。
答案
(a) 因为预测准确率是一个关于"观测分布"的量,
而参数是生成这个分布的机制。不同的机制可以生成几乎相同的观测分布,
这正是可辨识性问题的定义。用 §3.5.3 的原话说:
两组参数对"下一个观测是什么"给出几乎一样的答案,
但对"这个学生现在处于什么状态、接下来该给他多少练习"给出完全不同的答案。
(b) 教科书流程会选 B(AUC 0.7711 > 0.7646,对数似然也更高)。
这个选择危险,因为那 0.0065 的差距完全在噪声范围内,
§4.1 讲过,AUC 的抽样波动随样本量变化,在 100 个学生的规模上,
0.0065 的差异几乎肯定不显著。更重要的是:你选的是"哪个模型拟合得更好",
而你要的是"这个学生学会没有、还要练几次",
后一个问题上,B 会给出 17 次,A 会给出 52 次。
用一个在噪声里的差异,去决定一个差三倍的教学决策。
(c) 关键洞察:A 和 B 的差别只在 $P(T)$(0.05 vs 0.15),
而"学习率"的效应只在足够多的时间步之后才显现出来。
所以你需要更长的练习序列(§3.5.4 提过:把 N_ITEM 从 8 提到 30)。
具体做法:让每个学生把同一个技能练 30–50 次,
然后比较两种参数下的拟合优度。
原理:$P(T)$ 高意味着"从不会到会"的转变发生得更早、更频繁;
如果序列只有 8 步,大部分学生还没经历到那个转变序列就结束了,
于是两类参数都能解释数据。
序列一长,"什么时候出现转折"这个信息就积累了,$P(T)$ 就能被定位。
⚠️ 但这里有一个现实困境(这是本题的真正难点):
如果你让每个学生练 50 次同一技能,你的实验就不再是"自然的学习场景"了,
学生会疲劳、会无聊、会开始乱点。所以"为了可辨识性而收集更多数据"
和"数据的生态效度"是冲突的。
这个冲突没有技术解,只能靠研究者权衡。
12.4 第 4 题(AUC 手算)★★
6 个学生,模型给的"会挂科"风险分数与真实结果如下:
| 学生 | A | B | C | D | E | F |
|---|---|---|---|---|---|---|
| 分数 | 0.90 | 0.60 | 0.75 | 0.80 | 0.60 | 0.55 |
| 真挂科 | 是 | 是 | 否 | 是 | 否 | 否 |
(a) 用定义(配对法)手算 AUC。
(b) 用秩和公式核对。
(c) 如果把 A 的分数从 0.90 改成 0.92,AUC 会变吗?
答案
(a) 配对法。正样本(真挂科)3 个:A=0.90、B=0.60、D=0.80。
负样本 3 个:C=0.75、E=0.60、F=0.55。配对总数 $3\times3=9$。
| 配对 | 比较 | 结果 |
|---|---|---|
| A(0.90) vs C(0.75) | 0.90 > 0.75 | 正 > 负 ✓ |
| A(0.90) vs E(0.60) | 0.90 > 0.60 | 正 > 负 ✓ |
| A(0.90) vs F(0.55) | 0.90 > 0.55 | 正 > 负 ✓ |
| B(0.60) vs C(0.75) | 0.60 < 0.75 | 正 < 负 ✗ |
| B(0.60) vs E(0.60) | 并列 | 计半分 |
| B(0.60) vs F(0.55) | 0.60 > 0.55 | 正 > 负 ✓ |
| D(0.80) vs C(0.75) | 0.80 > 0.75 | 正 > 负 ✓ |
| D(0.80) vs E(0.60) | 0.80 > 0.60 | 正 > 负 ✓ |
| D(0.80) vs F(0.55) | 0.80 > 0.55 | 正 > 负 ✓ |
正 > 负 7 对,并列 1 对,正 < 负 1 对。
$$\mathrm{AUC} = \frac{7 + 0.5\times1}{9} = \frac{7.5}{9} = \mathbf{0.8333}$$
(b) 秩和公式。把 6 个分数从小到大排序:0.55、0.60、0.60(并列)、0.75、0.80、0.90。
并列的两个 0.60 占第 2、3 位,取平均秩 2.5。于是各样本的秩:
| 样本 | A | B | C | D | E | F |
|---|---|---|---|---|---|---|
| 分数 | 0.90 | 0.60 | 0.75 | 0.80 | 0.60 | 0.55 |
| 秩 | 6 | 2.5 | 4 | 5 | 2.5 | 1 |
正样本(A、B、D)的秩之和 $= 6 + 2.5 + 5 = 13.5$。代入:
$$\mathrm{AUC} = \frac{13.5 - \frac{3\times4}{2}}{3\times3} = \frac{13.5-6}{9} = \mathbf{0.8333}\ \checkmark$$
⚠️ 注意 (a) 和 (b) 必须相等,如果你用"并列按出现顺序排名"(不做平均秩),
(b) 会算出 0.8889,和 (a) 对不上。这是我最开始写代码时踩的坑(§4.1 里提过)。
(c) 不会变。 AUC 只看排序,A 从 0.90 涨到 0.92 没有改变任何一对样本的相对顺序。
这就是"AUA 与阈值无关"的另一面:AUC 与分数的绝对大小无关。
推论:一个把所有人的分数都缩小 10 倍的模型,AUC 完全一样但校准完全崩了,
所以只报 AUC 而不报校准,是不够的(§4.5)。
12.5 第 5 题(指标判读)★
接着第 4 题的数据,阈值取 0.85 / 0.70 / 0.60 / 0.50,填出下表,
并回答:这个模型的 AUC 一直是 0.8333,为什么精确率能从 1.000 掉到 0.500?
| 阈值 | 预警人数 | 命中 | 误报 | 精确率 | 召回率 |
|---|---|---|---|---|---|
| 0.85 | |||||
| 0.70 | |||||
| 0.60 | |||||
| 0.50 |
答案
| 阈值 | 预警人数 | 命中 | 误报 | 精确率 | 召回率 |
|---|---|---|---|---|---|
| 0.85 | 1 | 1 | 0 | 1.000 | 0.333 |
| 0.70 | 3 | 2 | 1 | 0.667 | 0.667 |
| 0.60 | 3 | 2 | 1 | 0.667 | 0.667 |
| 0.50 | 6 | 3 | 3 | 0.500 | 1.000 |
为什么 AUC 不变而精确率会变? 因为它们量的东西不同:
AUC 量的是"整个排序的质量",它把所有可能的阈值一起考虑了;
而精确率是在某一个具体阈值上算的,它只看到"被预警的那几个人"。
⚠️ 顺便注意 0.70 和 0.60 两行完全一样,因为在这两个阈值之间没有样本。
这说明"阈值"这个连续量在实际数据上只有有限个有效取值,
所以"我们调了一下阈值"这种说法,可能只是"换了一档",数字的跳跃感会给人虚假的精度感。
12.6 第 6 题(外推)★★
接 §4.4。假设你拟合出两条曲线:幂律 $P(n) = 0.85 - 0.70\,n^{-0.6}$
和指数 $P(n) = 0.80 - 0.75\,e^{-0.15n}$。
(a) 算出 $n=1,5,30,100,1000$ 时两者的预测值。
(b) 在 $n\le30$ 的范围内,两者的最大差异有多大?和数据的噪声比呢?
(c) 如果你要预测"这个学生练到 100 次时的正确率",你能用这批数据回答吗?
答案
(a)
| $n$ | 1 | 5 | 30 | 100 | 1000 |
|---|---|---|---|---|---|
| 幂律 | 0.1500 | 0.5835 | 0.7590 | 0.8058 | 0.8389 |
| 指数 | 0.1545 | 0.4457 | 0.7917 | 0.8000 | 0.8000 |
(这两行数字我逐个用 numpy 算过,见本页 §4.4 那套代码的同款写法。)
(b) 本题这两条曲线在 $n\le30$ 内最大差 0.1661(出现在 $n=3$ 附近),
到 $n=30$ 处缩到 0.0326。
但"最大差距"不是本题要看的量,因为差距最大的那几个点($n=2\sim6$),
恰恰是数据本身最不确定的地方。真正的判断标准是:
§4.4 用实际拟合出来的两条曲线,在 $n\le30$ 内的最大差距是 0.0518,
而观测数据本身的二项噪声标准差是 0.052。
两个模型的系统性差异,和数据自身的随机噪声一样大,
这意味着在现有数据范围内,你无法用拟合优度区分它们。
(c) 不能。因为 $n=100$ 处没有任何数据,
两个模型在这里分歧是 0.8058 vs 0.8000,
看起来差不多?但它们的趋势完全不同:
- 幂律还在缓慢上升($n=1000$ 时到 0.8389,仍未到天花板 0.85);
- 指数已经基本躺平($n=100$ 时 0.8000,$n=1000$ 时还是 0.8000)。
所以如果问题是"他还需要练多久",两个模型会给出完全不同的答案:
幂律说"继续练还有收益",指数说"练到 50 次就到头了,别再练了"。
这正是 Heathcote 等 (2000) 那个争论的实际后果,
它关乎"还要不要继续练"这个教学决策,跟"哪个公式更漂亮"无关。
⭐ 把第 3 题和第 6 题放在一起看:它们是同一个结构。
数据能约束的区域里,模型之间没有差别;有差别的区域里,没有数据。
"哪个模型对"这个问题,最终要靠"你愿意假设哪个函数族"来回答。
12.7 第 7 题(白质通路)★★
(a) 一位同学说:"弓状束连接布洛卡区和韦尼克区,负责语言的产生和理解。"
这句话里有几处需要修改?逐条改。
(b) §6.3 的表里,哪几条通路的存在性本身有争议?为什么"存在性有争议"和"功能有争议"是两件不同的事?
答案
(a) 至少四处:
- "连接布洛卡区和韦尼克区",更准确的表述是"连接额下回(BA 44/45,岛的盖部/三角部)
与后部颞上回(及颞中回)"。
"布洛卡区/韦尼克区"是 19 世纪的临床术语,边界模糊;
现代文献用解剖学命名。而且按不同作者的方案,
弓状束有时被算作上纵束的一段(Makris 的方案)而不是独立束。 - "负责语言的产生和理解",这是把"连接"直接等同于"功能",是一个不成立的等式。
准确说法是:弓状束的损伤与复述困难(传导性失语)相关;
"相关"不等于"负责"。而且现代观点不认为"产生"和"理解"是两个中心,
失语症和脑成像都表明布洛卡区也参与理解(见《语言认知神经科学》§4)。 - 它没有提"左侧优势"这个限定,弓状束总体呈左侧优势
(Catani 等 2007 报告约 80% 右利手在长直段上左偏)。 - 它把弓状束当成语言网络的主干,实际上语言依赖一组通路:
背侧(弓状束/SLF)+ 至少两条腹侧通路(钩束、极端囊纤维系统/IFOF),
而且腹侧通路对语义是必需的。只讲弓状束 = 只讲了半个网络。
(加分项):如果这位同学还说了"所以语言就是额叶和颞叶两个点在对话",
那么还要指出:现代观点是分布式网络,而且"两个点在对话"这个图景
忽略了白质通路的功能不只取决于它连了谁,还取决于什么时候被激活。
(b) 存在性有争议的:IFOF(猴的示踪研究未能证实人类对应物)、
MdLF(经典解剖研究未描述,部分纤维解剖未能证实,支持证据主要来自弥散追踪)。
SLF 的偏侧化方向有争议(Makris 等报告左优势,Budisavljevic 等报告 SLF III 右优势)。
"存在性"和"功能"为什么是两件事:
- 存在性是一个解剖学问题,可以用纤维解剖、追踪、组织学来回答
(虽然方法各有偏差)。它原则上有一个"是/否"的答案。 - 功能是一个认知神经科学问题,它问的是"这条束在什么条件下、
通过什么机制参与什么认知过程"。这个问题无法只靠解剖回答,
它需要损伤研究、电刺激、功能连接等多类证据。 - 所以一条束可以"确定存在但功能不明"(比如 FAT 的存在很清楚,
但它和口吃的关系还在研究中),
也可以"存在有争议但功能假说很流行"(IFOF 是这种情况的典型:
它在很多语言模型里被当作腹侧语义通路的关键一环,
但它的解剖存在性本身在跨物种比较上就站不稳)。
⭐ 这一题的真正考点:"某条束参与语言"这句话,需要同时报告
① 束本身的存在性证据有多硬,② 功能结论是用什么方法得到的。
只报告后面一半,是这一领域最常见的引用错误。
12.8 第 8 题(双语优势)★★
(a) 下面三句话,哪句是准确的?为什么另外两句不准确?
① "研究证明双语能提升认知能力。"
② "研究证明双语优势不存在。"
③ "早期研究报告了双语者在执行功能任务上的优势,但后续的大样本研究和
校正发表偏倚的元分析没有支持这个结论。"
(b) de Bruin 等 (2015) 的研究方法有什么特别之处?为什么这个设计比普通的元分析更能说明问题?
答案
(a) 只有 ③ 准确。
- ①的问题:把"早期小样本研究的阳性结果"说成了"研究证明"。
在 Lehtonen 等 (2018) 校正发表偏倚之后,所有领域的优势都消失了。
而且"认知能力"太笼统,双语确实改变语言系统本身,
但"一般认知能力"这个更强的说法没有被支持。 - ②的问题:"没有证据支持"不等于"证明不存在"。
二者在统计上是不同的(零结果可能来自样本量不足、测量不敏感),
在认识论上也不该混用。而且"双语"是一个极粗的变量,
它可能掩盖了具体维度的真实效应。 - ③的问题:无。它同时交代了早期结果、后续证据、失效原因,
而且用的是"没有支持"而不是"证明不存在"。
(b) de Bruin 等没有看已发表的论文,而是去找会议摘要,
1999–2012 年间 169 个会议上的 104 份摘要,
然后追踪哪些摘要最终变成了论文。结果:支持双语优势的摘要约 68% 被发表,
而挑战它的只有约 29%。
为什么这个设计更强:因为元分析只能看到"被发表的东西",
如果发表过程本身筛掉了阴性结果,那么一个纳入标准再严格的元分析,
它的输入样本也是被污染过的。
会议摘要是"几乎所有做过这项研究的人"都留下的痕迹,
它让我们能看到"文件抽屉"(file drawer)里有什么。
这就是著名的"文件抽屉问题"的一个漂亮解法:
不去研究结果,而去研究"结果的流动"。
⚠️ 数字的提醒:我在 §7.3 里给了约 68% / 29% 这一组数字,
同时注明"不同报道里有 63%/36% 的版本,分母定义不同"。
引用具体百分比时请核对原文表格。
12.9 第 9 题(语言网络 vs 多需求系统)★★★
(a) 用一句话分别说出"语言网络与 MD 系统重叠"和"两者分离"各自的
最硬证据。
(b) §8.2.3 的模拟说明了什么机制?它和真实研究里的机制是同一个吗?
(c) 设计一个实验,能在同一个被试群体上同时检验"重叠"和"分离"两个说法。
关键的控制条件是什么?
答案
(a)
- 支持重叠的最硬证据:左额下回(布洛卡区)内部同时包含语言选择性和域一般的子区,
它们相邻但可分离(Fedorenko, Duncan & Kanwisher 2012, Current Biology)。
也就是说,在"布洛卡区"这个粗标签下,确实装着两类不同的东西。 - 支持分离的最硬证据:逐被试定位语言区之后,语言区对非语言难任务
(算术、工作记忆、认知控制、音乐)几乎不反应,
而这些任务在附近区域引起了强烈激活(Fedorenko, Behr & Kanwisher 2011, PNAS)。
关键在于每个非语言任务都设计了"难 vs 匹配的易"对照,
所以"语言区只是对难度反应"这个解释被排除掉了。
另一个强证据是两个系统的自发 BOLD 波动在静息和听故事时都弱相关或负相关
(Blank, Kanwisher & Fedorenko 2014, J. Neurophysiol.)。
(b) 模拟说明的机制是:当两类功能单元在空间上交错时,
"对它们求平均"会系统性地抹掉选择性,
在细尺度上每块都"很特异",在粗尺度上整块都"没选择性"。
⚠️ 和真实研究里的机制不是同一个,但属于同一类:
- 模拟里的机制是"你怎么划一个脑区(分区大小)";
- 真实研究里的机制是"跨被试平均 + 被试间解剖变异",
不同人的语言区位置有差异,把它们平均到一起,
相邻但不重叠的区域就会被抹成一片。
两者的共同数学操作是"对空间上交错的东西做平均"。
我在 §8.2.3 明确标注了这是模拟数据、选择性指数不是标准指标,
这一点必须保留,不能把模拟当成证据。
(c) 关键设计:
① 逐被试功能定位
用语言定位器(句子 vs 可发音非词)和 MD 定位器
(硬 vs 易的空间工作记忆)在每个被试身上各自划出两个网络
↓
② 关键控制:语言任务的"难 vs 易"对照
不能只做"读句子 vs 静息"——那会把努力、注意都算进去
要做"复杂句 vs 简单句"且匹配其他变量
↓
③ 关键控制:非语言任务的"难 vs 易"对照
这样才能排除"语言区只是对难度反应"
↓
④ 两个分析
重叠检验:两个网络的空间重叠率(在个体水平上算,不是群组平均)
分离检验:两个网络内部 vs 之间的 BOLD 波动相关
最重要的两个控制条件:
- 逐被试定位(而不是群组平均),
这直接针对 (b) 里那个"平均抹掉选择性"的机制。 - 难度匹配的对照条件(语言任务和非语言任务都要有),
这直接针对 §8.1 的"任务难度混淆"。
⭐ (c) 的本质:这两个控制条件都是"用设计消灭混淆",
而不是"用统计事后校正"。这是《实验方法论》的核心原则的应用:
你无法用统计方法补救一个设计缺陷。
12.10 第 10 题(综合:两门课的失效方式)★★★
这一题考的是整页的主线。
(a) 完成下表(不要翻回 §9,先自己写):
| 学习分析 | 语言与人脑 | |
|---|---|---|
| 想知道的(隐) | ||
| 能拿到的(显) | ||
| 连接两侧的核心假设 | ||
| 最典型的失效方式 | ||
| 一个具体的失效例子 |
(b) "两门课的失效方式不同,但都发生在同一个位置上。"这个"同一个位置"是什么?
(c) 给出一条同时适用于两门课的"读论文检查清单"(不超过 4 条)。
答案
(a)
| 学习分析 | 语言与人脑 | |
|---|---|---|
| 想知道的(隐) | 学生会不会、掌握到什么程度 | 语言加工在哪里、什么时候、怎么进行 |
| 能拿到的(显) | 点击流、作答对错、用时、求助次数 | BOLD 信号、ERP 波形、纤维束、损伤症状 |
| 连接两侧的核心假设 | 行为反映学习(含 $P(G)$/$P(S)$ 两个含噪通道) | 激活反映加工(含"纯插入"和"难度不混淆") |
| 最典型的失效方式 | 标签是含噪的代理变量 | 观测是多义的(一对多) |
| 一个具体的失效例子 | 答对里有 9% 是猜的;参数不可辨识(52 次 vs 17 次) | 反向推理;同一份脑数据在粗/细尺度上给出相反结论 |
(b) "同一个位置"是那个从"可观测信号"跨到"不可观测心理状态"的箭头。
更准确地说,是这根箭头两侧的对应关系不是一一对应的:
- 学习分析侧:多个心理状态 → 同一个观测(会而失误 / 不会而猜对,都产生"答对");
- 语言与人脑侧:同一个观测 → 多个心理状态(激活可以由很多不同的加工产生)。
这两种"非一一对应"在数学上是同一个问题的两个方向:
一个是从似然反推先验(贝叶斯反演,需要先验才能做),
一个是从观测反推原因(反向推理,需要特异性才能做)。
两者都要求一个"数据之外的输入",先验,或者特异性证据。
这就是为什么 §1 说"假设是全部信息的来源",而不是"假设是缺陷"。
(c) 一条通用清单(任选 4 条即可,以下给 5 条):
- 信号到心理状态那一步,用了什么假设?这个假设被独立检验过吗?
- 对照/基准是什么?(教育:基准线模型是多少?神经:对照条件是静息还是匹配任务?)
- 分辨率/尺度是什么?换个尺度结论会变吗?(教育:按什么粒度汇总?神经:分区多大、平均了谁?)
- 结论对"多义性"做了什么处理?(教育:报告参数不确定性了吗?神经:报告特异性了吗?)
- 有没有一个能"否证"这个结论的实验?(如果一个结论在任何数据下都成立,它没有信息量。)
⭐ 本题的评分要点:(a) 和 (c) 是记忆和迁移,(b) 是理解。
(b) 答对,说明你抓住了这一页的主线;
(b) 答成"都在做统计"或者"都要用数据",说明还停留在表面。
13 出处索引
⚠️ 使用说明:下表所有文献我都尽可能核对过(期刊、卷期、页码)。
凡是核对不上的,我标了"出处待查"或"⚠️"。
引用前请以原文为准,尤其是那些我明确标了"数值来自转述"的条目。
13.1 学习分析:知识追踪与 BKT
| 文献 | 出处 | 本页位置 |
|---|---|---|
| Corbett, A. T., & Anderson, J. R. (1995). Knowledge tracing: Modeling the acquisition of procedural knowledge | User Modeling and User-Adapted Interaction, 4(4), 253–278 · DOI 10.1007/BF01099821 | §3.2–§3.3(BKT 全部公式) |
| Anderson, J. R. (1993). Rules of the Mind | Erlbaum | §3.2(BKT 的 ACT-R 来源) |
| Atkinson, R. C. (1972). Optimizing the learning of a second-language vocabulary | Journal of Experimental Psychology, 96(1), 124–129 | §3.2(贝叶斯形式的更早来源,⚠️ 卷期页码我未逐项核对) |
| Reye, J. (2004). Student modelling based on belief networks | International Journal of Artificial Intelligence in Education, 14(1), 63–96 | §3.2(BKT 等价于 DBN/HMM,⚠️ 页码未逐项核对) |
| Piech, C., et al. (2015). Deep Knowledge Tracing | NeurIPS 2015 · arXiv:1506.05908 | §3.6(DKT) |
| Pardos, Z. A., & Heffernan, N. T. (2010). Modeling individualization in a Bayesian networks implementation of knowledge tracing | UMAP 2010 | §3.5.4(个体化先验 PPS,⚠️ 会议信息未逐项核对) |
| Baker, R. S., Corbett, A. T., & Aleven, V. (2008). More accurate student modeling through contextual estimation of slip and guess probabilities in Bayesian knowledge tracing | ITS 2008 | §3.6(对 P(G)/P(S) 的批评,⚠️ 页码未核对) |
⚠️ 关于 BKT 参数取值:本页用的 $P(L_0)=0.30$、$P(T)=0.10$、$P(G)=0.20$、$P(S)=0.10$
是教学示意取值,不是 Corbett & Anderson 原论文的参数。
原论文是对每个技能分别拟合参数的(21 条规则),并报告了两组拟合优度:
参数固定时 $r=0.47$,参数随规则变化时 $r=0.85$
(⚠️ 这两个数字来自我对该论文的二手转述,我没有直接核对原表,引用前请查原文)。
13.2 学习分析:EDM / 学习分析 / 伦理
| 文献 | 出处 | 本页位置 |
|---|---|---|
| Baker, R. S. J. D., & Yacef, K. (2009). The state of educational data mining in 2009: A review and future visions | Journal of Educational Data Mining, 1(1), 3–17 | §2.1(四大任务与趋势) |
| Siemens, G., & Long, P. (2011). Penetrating the fog: Analytics in learning and education | EDUCAUSE Review, 46(5), 30–40(页码各版本略有出入,见下) | §2(学习分析的背景) |
| LAK 2011(第一届学习分析与知识国际会议)对 learning analytics 的定义 | 会议定义,常与 Siemens & Long (2011) 并引 | §2(开头的定义) |
| Romero, C., & Ventura, S. (2010). Educational data mining: A review of the state of the art | IEEE Trans. Systems, Man, and Cybernetics Part C, 40(6), 601–618 | §2.1(⚠️ 卷期页码未逐项核对) |
| Romero, C., & Ventura, S. (2020). Educational data mining and learning analytics: An updated survey | WIREs Data Mining and Knowledge Discovery, 10(3), e1355 | §2.1(⚠️ 未逐项核对) |
| Slade, S., & Prinsloo, P. (2013). Learning analytics: Ethical issues and dilemmas | American Behavioral Scientist, 57(10), 1510–1529 | §5.2(权力、监控、学生身份的暂时性) |
| Bloom, B. S. (1984). The 2 sigma problem: The search for methods of group instruction as effective as one-to-one tutoring | Educational Researcher, 13(6), 4–16 | §10.2(⚠️ 卷期页码未逐项核对) |
| VanLehn, K. (2011). The relative effectiveness of human tutoring, intelligent tutoring systems, and other tutoring systems | Educational Psychologist, 46(4), 197–221 · DOI 10.1080/00461520.2011.611369 | §10.2(ITS $d\approx0.76$;人类辅导 $d\approx0.79$) |
| Kulik, J. A., & Fletcher, J. D. (2016). Effectiveness of intelligent tutoring systems: A meta-analytic review | Review of Educational Research, 86(1), 42–78 · DOI 10.3102/0034654315581420 | §10.2(50 项评价,中位数 $d=0.66$) |
| Steenbergen-Hu, S., & Cooper, H. (2013). A meta-analysis of the effectiveness of intelligent tutoring systems on K–12 students' mathematical learning | Journal of Educational Psychology, 105(4), 970–987 · DOI 10.1037/a0032447 | §10.2($g=0.01\sim0.09$;低成就学生受益更少) |
| Heathcote, A., Brown, S., & Mewhort, D. J. K. (2000). The power law repealed: The case for an exponential law of practice | Psychonomic Bulletin & Review, 7(2), 185–207 | §4.4(幂律 vs 指数) |
| Newell, A., & Rosenbloom, P. S. (1981). Mechanisms of skill acquisition and the law of practice | 收入 Anderson (ed.), Cognitive Skills and Their Acquisition, Erlbaum, 1–55 | §4.4(幂律的经典来源,⚠️ 页码未核对) |
13.3 语言与人脑:框架与综述
| 文献 | 出处 | 本页位置 |
|---|---|---|
| Hickok, G., & Poeppel, D. (2007). The cortical organization of speech processing | Nature Reviews Neuroscience, 8(5), 393–402 · DOI 10.1038/nrn2113 | §6.2.1(双流模型;详见《语言认知神经科学》§6) |
| Friederici, A. D. (2011). The brain basis of language processing: From structure to function | Physiological Reviews, 91(4), 1357–1392 · DOI 10.1152/physrev.00006.2011 | §6.2.2(背-腹通路模型) |
| Hagoort, P. (2005). On Broca, brain, and binding: A new framework | Trends in Cognitive Sciences, 9(9), 416–423 | §6.2.3(MUC 的前身,⚠️ 页码未逐项核对) |
| Hagoort, P. (2013). MUC (Memory, Unification, Control) and beyond | Frontiers in Psychology, 4, Article 416 | §6.2.3(MUC 模型原始出处) |
| Hagoort, P., & Indefrey, P. (2014). The neurobiology of language beyond single words | Annual Review of Neuroscience, 37, 347–362 · DOI 10.1146/annurev-neuro-071013-013847 | §6.2.2(背-腹梯度的元分析支持) |
| Hagoort, P. (2019). The neurobiology of language beyond single-word processing | Science, 366(6461), 55–58 · DOI 10.1126/science.aax0289 | §6.2.3(⚠️ 注意:这一篇在 Science,不是 Annual Review,见 §6.2.3 的更正说明) |
13.4 语言与人脑:白质通路
| 文献 | 出处 | 本页位置 |
|---|---|---|
| Catani, M., Jones, D. K., & ffytche, D. H. (2005). Perisylvian language networks of the human brain | Annals of Neurology, 57(1), 8–16 | §6.3.1(AF 三段分法,⚠️ 页码未逐项核对) |
| Catani, M., et al. (2007). Symmetries in human brain language pathways correlate with verbal recall | PNAS, 104(43), 17163–17168 | §6.3.1(AF 左偏侧约 80%/60%,⚠️ 数字来自二手转述,请核对原文) |
| Makris, N., et al. (2005). Segmentation of subcomponents within the superior longitudinal fascicle in humans | Cerebral Cortex, 15(6), 854–869 | §6.3.1(SLF I–IV 分段;AF = SLF IV,⚠️ 页码未核对) |
| Budisavljevic, S., Dell'Acqua, F., Zanatto, D., Begliomini, C., Miotto, D., Motta, R., & Castiello, U. (2017). Asymmetry and structure of the fronto-parietal networks underlie visuomotor processing in humans | Cerebral Cortex, 27(2), 1532–1544 · DOI 10.1093/cercor/bhv348 | §6.3.1(SLF I/II 左优势、SLF III 右优势;后续被 Cazzoli & Chechlacz (2017) 与 Amemiya 等 (2021, Cortex) 复现) |
| Forkel, S. J., et al. (2014). The anatomy of fronto-occipital connections from early blunt dissections to contemporary tractography | Cortex, 56, 73–84 · DOI 10.1016/j.cortex.2012.09.005 | §6.3.2(IFOF 的历史与争议;个体间重叠 40%–90%) |
| Kalyvas, A., et al. (2020). Mapping the human middle longitudinal fasciculus through a focused anatomo-imaging study | Brain Structure and Function, 225(1), 85–119 · DOI 10.1007/s00429-019-01987-6 | §6.3.2(MdLF 分段与功能改判) |
| Latini, F., et al. (2021). 对 MdLF 的尸检+活体追踪研究(两段方案) | Frontiers in Neuroanatomy(⚠️ 完整的卷号/文章号我未能确认,标"出处待查") | §6.3.2(MdLF 的两段 vs 三段之争) |
| Wang, Y., et al. (2012). Rethinking the role of the middle longitudinal fascicle in language and auditory pathways | Cerebral Cortex(⚠️ 卷期页码未核对) | §6.3.2(MdLF 的听觉假说) |
| Dick, A. S., Bernal, B., & Tremblay, P. (2014). The language connectome: New pathways, new concepts | The Neuroscientist, 20(5), 453–467 | §6.3("语言连接组"的整体框架,⚠️ 未逐项核对) |
| Dronkers, N. F., et al. (2007). Paul Broca's historic cases: High resolution MR imaging of the brains of Leborgne and Lelong | Brain, 130(5), 1432–1441 | §6.1(Leborgne 重扫;详见《语言认知神经科学》§4) |
13.5 语言与人脑:双语
| 文献 | 出处 | 本页位置 |
|---|---|---|
| Bialystok, E., Craik, F. I. M., Klein, R., & Viswanathan, M. (2004). Bilingualism, aging, and cognitive control: Evidence from the Simon task | Psychology and Aging, 19(2), 290–303 | §7.3(早期支持性研究) |
| Abutalebi, J., & Green, D. (2007). Bilingual language production: The neurocognition of language representation and control | Journal of Neurolinguistics, 20(3), 242–275 | §7.2(语言控制网络) |
| Abutalebi, J., & Green, D. W. (2016). Neuroimaging of language control in bilinguals: Neural adaptation and reserve | Bilingualism: Language and Cognition, 19(4), 689–698 | §7.2(⚠️ 卷期页码未逐项核对) |
| Paap, K. R., & Greenberg, Z. I. (2013). There is no coherent evidence for a bilingual advantage in executive processing | Cognitive Psychology, 66(2), 232–258 | §7.3(证据四) |
| de Bruin, A., Treccani, B., & Della Sala, S. (2015). Cognitive advantage in bilingualism: An example of publication bias? | Psychological Science, 26(1), 99–107 · DOI 10.1177/0956797614557866 | §7.3(证据一:发表偏倚) |
| Lehtonen, M., Soveri, A., Laine, A., Järvenpää, J., de Bruin, A., & Antfolk, J. (2018). Is bilingualism associated with enhanced executive functioning in adults? A meta-analytic review | Psychological Bulletin, 144(4), 394–425 · DOI 10.1037/bul0000142 | §7.3(证据二:152 项研究、891 个效应量) |
| Nichols, E. S., Wild, C. J., Stojanoski, B., Battista, M. E., & Owen, A. M. (2020). Bilingualism affords no general cognitive advantages: A population study of executive function in 11,000 people | Psychological Science, 31(5), 548–567 · DOI 10.1177/0956797620903113 | §7.3(证据三:11,041 人、12 项任务) |
13.6 语言与人脑:语言网络与多需求系统
| 文献 | 出处 | 本页位置 |
|---|---|---|
| Duncan, J. (2010). The multiple-demand (MD) system of the primate brain: Mental programs for intelligent behaviour | Trends in Cognitive Sciences, 14(4), 172–179 | §8.2(MD 系统的提出) |
| Fedorenko, E., Behr, M. K., & Kanwisher, N. (2011). Functional specificity for high-level linguistic processing in the human brain | PNAS, 108(39), 16428–16433 · DOI 10.1073/pnas.1112937108 | §8.2.2(语言区对非语言难任务不反应) |
| Fedorenko, E., Duncan, J., & Kanwisher, N. (2012). Language-selective and domain-general regions lie side by side within Broca's area | Current Biology, 22(21), 2059–2062 | §6.1、§8.2.1(布洛卡区内部的两种子区) |
| Fedorenko, E., Duncan, J., & Kanwisher, N. (2013). Broad domain generality in focal regions of frontal and parietal cortex | PNAS, 110(41), 16616–16621 | §8.2.1(额顶的域一般区域) |
| Blank, I. A., Kanwisher, N., & Fedorenko, E. (2014). A functional dissociation between language and multiple-demand systems revealed in patterns of BOLD signal fluctuations | Journal of Neurophysiology, 112(5), 1105–1118 · DOI 10.1152/jn.00884.2013 | §8.2.2(两系统波动弱相关/负相关) |
| Fedorenko, E., & Blank, I. A. (2020). Broca's area is not a natural kind | Trends in Cognitive Sciences, 24(9), 692–704 | §8.2.4(⚠️ 卷期页码未逐项核对) |
13.7 我明确没能完全确认的地方(如实标注)
-
de Bruin 等 (2015) 的具体百分比(§7.3、§11 第 8 题):
我看到 68% / 29% 和 63% / 36% 两组数字,
差异来自"完全支持/混合支持"如何归类、以及分母的定义。
本页给了两组数字并标注了这一点。引用前请核对原文的表格。 -
Catani 等 (2007) 的"80% / 60%"(§6.3.1):
这两个数字来自我对该文献的二手转述(搜索摘要),
我没有直接读到原表。"约 80% 的右利手呈左偏侧"这个说法在多处出现,
看起来是稳的;但"约 60% 极端左偏"这个更具体的数字,我没有独立确认。
引用时建议只写"总体左侧优势",或标注数字来源待核。 -
SLF III 的偏侧化方向(§6.3.1),这一条我在写作中查清了,留在这里作为记录:
冲突双方是 Makris 等 (2005)(报告左侧优势,用 FA 和各向异性指数)
与 Budisavljevic 等 (2017)(报告右侧优势,用流线数和束体积),
后者后来被 Cazzoli & Chechlacz (2017) 和 Amemiya 等 (2021, Cortex) 复现。
所以"SLF III 偏侧化方向有争议"是准确的;
但要注意双方用的是不同的测量指标,这可能正是结论相反的原因之一。
(教训:看到"某某结构左侧优势"时,问一句"用的什么指标"。
同一批纤维,换个指标就可能翻边。)
另外两处需要提醒的:
- Steenbergen-Hu & Cooper 的"低成就学生受益更少"(§10.2):
一项2025 年的 arXiv 预印本报告没有复现这个差异。
我无法确认该预印本是否已过同行评议,本页已注明"预印本"。 - Kulik & Fletcher 的"0.73 vs 0.13"(§10.2):
来自对该综述的转述(一份会议演示材料),不是原文表格。
本页已明确标注,引用前请核对原文。
最后一句:这一页的所有代码我都实跑过(共 9 个脚本,
从 §2.2 的 EDM 演示到 §8.2.3 的模拟),
所有引用的数字要么来自我实际运行的输出,要么标注了文献出处或"转述/待查"。
如果哪一处你复现不出来,请以你的实际输出为准,这可能是我漏掉的环境差异。
14 相关
../专业课/教材/笔记-认知神经科学核心.html,§2 BOLD 与 HRF、§6 三个误解
(尤其是反向推理那一段的贝叶斯算式)是本页 §8.1、§9 的直接地基。../专业课/教材/笔记-语言认知神经科学.html,§4 失语症、§5 "95% 在左脑"的数字追踪、
§6 双流模型。本页 §6 明确不重复那里,只讲"那之后发生了什么"。../专业课/教材/笔记-实验方法论核心.html,§4 的"指标决定结论"、
§5 的重复危机、RCT 与因果推断。本页 §4.3 和 §7.3 都是那套标准的应用实例。../专业课/教材/笔记-教育评价.html,测量、信度效度、以及"怎么把能力测准"。
本页 §4 讲的是"怎么从过程数据预测",两者目标不同,值得对照读。../专业课/教材/笔记-教育统计学.html,本页 §3.5 的可辨识性、§4.1 的 AUC,
在那门课里有更正式的统计处理(最大似然、置信区间、模型选择)。深度学习原理与实践.md,§7 RNN/LSTM 是本页 §3.6 提到的 DKT 的技术底座。自然语言处理.md,§7 的评测指标(BLEU/F1 及其缺陷)和本页 §4 讲的是同一类问题:
指标是一个"把多维现实压成一维"的操作,压缩方式决定了你能看到什么。大语言模型理论与实践.md,§10.4 提到的"大模型时代的 ITS",
技术细节在那门课,批评部分请回到本页 §4.3 和 §5。