▤书架 ← 返回索引
▶目录

阶段 08 讲义

数学 11h:线代 · 行列式与克拉默法则
编程 9h:字典与集合


第一部分 · 数学

从这一阶段开始,我们从"高数"进入"线性代数"。

线代的对象是方程组,而行列式是解方程组的一把钥匙。先把工具磨好,阶段 9 才开始算矩阵。

1 二阶行列式

问题:解二元一次方程组

$$\begin{cases} a_{11}x + a_{12}y = b_1 \\ a_{21}x + a_{22}y = b_2 \end{cases}$$

用消元法解(第一个方程乘 $a_{22}$,第二个乘 $a_{12}$,相减):

$$(a_{11}a_{22} - a_{12}a_{21})x = b_1a_{22} - a_{12}b_2$$

分母那个东西反复出现,于是数学家给它起了个名字:

$$\begin{vmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \end{vmatrix} = a_{11}a_{22} - a_{12}a_{21}$$

记忆:主对角线乘积 − 副对角线乘积。

💡 记号:两条竖线是行列式,和矩阵的方括号 [ ] / 圆括号 ( ) 不是一回事。
行列式算出来是一个数;矩阵是一张表。

例子:

$$\begin{vmatrix} 2 & 1 \\ 1 & -3 \end{vmatrix} = 2\times(-3) - 1\times1 = -6-1 = -7$$

2 三阶行列式:萨吕斯法则

$$\begin{vmatrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \end{vmatrix}$$

萨吕斯法则(对角线法则):

① 三条"主方向"对角线相乘,相加

$$a_{11}a_{22}a_{33} + a_{12}a_{23}a_{31} + a_{13}a_{21}a_{32}$$

② 三条"副方向"对角线相乘,相减

$$-\; a_{13}a_{22}a_{31} - a_{12}a_{21}a_{33} - a_{11}a_{23}a_{32}$$

⚠️ 萨吕斯法则只对二阶和三阶成立!四阶以上不能这样算。
四阶以上要用按行(列)展开,或者直接上计算机。

手算技巧:把前两列抄到右边,画 6 条对角线,

$$\begin{vmatrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \end{vmatrix} \begin{matrix} a_{11} & a_{12} \\ a_{21} & a_{22} \\ a_{31} & a_{32} \end{matrix}$$

↘ 方向三组相加,↗ 方向三组相减。

2.1 完整例子

计算 $\begin{vmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 10 \end{vmatrix}$

↘ 主方向(相加):

$$1\cdot5\cdot10 + 2\cdot6\cdot7 + 3\cdot4\cdot8 = 50 + 84 + 96 = 230$$

↗ 副方向(相减):

$$3\cdot5\cdot7 + 2\cdot4\cdot10 + 1\cdot6\cdot8 = 105 + 80 + 48 = 233$$

结果:

$$230 - 233 = -3$$

⚠️ 手算最容易错的地方:把 6 条对角线漏掉一条。
建议按顺序数:主方向从左上角开始,依次取三个起点;副方向同理。
算完核对一下,是不是正好 6 项?

3 行列式的性质 ⭐(用来简化计算)

直接按定义算三阶很累。性质才是真正的工具,它们让你不算就能得出结论。

# 性质 直观理解
1 $\det(I)=1$ 单位阵不变形
2 交换两行(列),行列式变号 翻转方向
3 某行(列)乘 $k$,行列式乘 $k$ 拉伸 $k$ 倍
4 两行(列)相同 → 行列式 = 0 冗余
5 某行是另一行的倍数 → 行列式 = 0 冗余
6 某行加上另一行的 $k$ 倍,行列式不变 剪切不改变面积
7 $\det(A^T) = \det(A)$ 行列对等
8 $\det(AB) = \det(A)\det(B)$ 复合变换的伸缩
9 上(下)三角行列式 = 对角线乘积 只剩对角

3.1 这些性质怎么用

用法一:不算就知道是 0(性质 4、5)

$$\begin{vmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 2 & 4 & 6 \end{vmatrix} = 0 \quad\text{(第 3 行 = 第 1 行 × 2)}$$

一眼看出,不用算。这在考试里能省大量时间。

用法二:化成三角形(性质 6 + 性质 9)

用"某行加另一行倍数"把行列式化成上三角,然后对角线一乘就完事:

$$\begin{vmatrix} 1 & 2 & 3 \\ 0 & 4 & 5 \\ 0 & 0 & 6 \end{vmatrix} = 1\times4\times6 = 24$$

💡 这是计算机算行列式的实际方法(高斯消元)。性质 6 是它的核心,
因为只有"行加行倍数"不改变行列式的值,可以放心用。

验证(数值):

性质 检验
交换两行变号 $\det$ 从 $41 \to -41$ ✓
某行 ×2 $\det$ 从 $41 \to 82$ ✓
两行相同 $\det = 0$ ✓
上三角 $1\cdot4\cdot6 = 24$ ✓
$\det(AB)=\det A\det B$ 两边都是 $-574$ ✓

4 克拉默法则 ⭐

有了行列式,方程组的解可以直接写出来。

对 $n$ 个方程、$n$ 个未知数的方程组(系数行列式 $D \ne 0$):

$$x_1 = \frac{D_1}{D}, \quad x_2 = \frac{D_2}{D}, \quad \dots, \quad x_n = \frac{D_n}{D}$$

其中 $D_i$ 是"把 $D$ 的第 $i$ 列换成常数列"得到的行列式。

4.1 完整例子(二阶)

解 $\begin{cases} 2x + y = 5 \\ x - 3y = -1 \end{cases}$

第一步,算系数行列式:

$$D = \begin{vmatrix} 2 & 1 \\ 1 & -3 \end{vmatrix} = -6-1 = -7$$

第二步,用常数列替换:

$$D_1 = \begin{vmatrix} \mathbf{5} & 1 \\ \mathbf{-1} & -3 \end{vmatrix} = -15-(-1) = -14 \qquad (\text{第 1 列换成 } 5,-1)$$

$$D_2 = \begin{vmatrix} 2 & \mathbf{5} \\ 1 & \mathbf{-1} \end{vmatrix} = -2-5 = -7 \qquad (\text{第 2 列换成 } 5,-1)$$

第三步,相除:

$$x = \frac{D_1}{D} = \frac{-14}{-7} = 2, \qquad y = \frac{D_2}{D} = \frac{-7}{-7} = 1$$

验根:$2(2)+1=5$ ✓,$2-3(1)=-1$ ✓

4.2 ⚠️ 克拉默法则的局限(很重要)

① 必须 $D \ne 0$

$D=0$ 时不能用。此时方程组要么无解,要么有无穷多解,

$$\begin{cases} x + 2y = 3 \\ 2x + 4y = 6 \end{cases} \implies D = \begin{vmatrix} 1 & 2 \\ 2 & 4 \end{vmatrix} = 0$$

第二个方程是第一个的 2 倍,只有一个独立方程,$y$ 可以随便取 → 无穷多解。

② 方程个数必须等于未知数个数

3 个未知数、2 个方程?克拉默法则管不了。

③ 数值上不实用(这条最重要)

为什么实际计算不用它:

维度 计算量
算 $n+1$ 个 $n$ 阶行列式 $O(n \cdot n!)$ 级别
高斯消元法 $O(n^3)$

$n=20$ 时,$20! \approx 2.4\times10^{18}$,宇宙年龄都算不完。
而 $20^3 = 8000$,一瞬间。

💡 所以克拉默法则的价值在"理论",不在"计算":
- 它给出了解的显式公式,能用来证明定理(比如解对参数的连续依赖)
- 但真要算数值,还得用消元法(numpy.linalg.solve 走的就是这条路)

这是数值计算的第一课:数学上"有公式"不等于"该用公式"。
阶段 3 的数值微分(h 不能太小)是同一个道理的另一面。


5 🧠 这跟认知科学有什么关系

这一节的对应关系是我验证过的(用代码实算),但心理学结论请对照文献。

行列式 = 0 ↔ 多重共线性(multicollinearity),回归分析里的大麻烦。

线性回归要求解 $X\beta = y$,正规方程是:

$$X^TX\beta = X^Ty$$

$X^TX$ 的行列式如果 = 0,这个方程组就无唯一解,回归系数算不出来。

这什么时候发生:当自变量之间线性相关时。最常见的场景是多重共线性:
两个自变量几乎携带同样的信息。

5.1 实算给你看

我构造了 30 个数据点,真实模型是 $y = 2 + 3x_1$,然后故意加一个几乎等于 $x_1$ 的 $x_2$:

$x_2$ 与 $x_1$ 的差距 $\det(X^TX)$ 条件数 解出的系数
差 5 左右(独立) $3.6\times10^{6}$ 20 $(1.98,\ 3.01,\ -0.005)$ ✓
差 0.5 $4.6\times10^{4}$ 27 $(1.98,\ 2.98,\ 0.02)$ ✓
差 0.01 $1.4\times10^{1}$ 1556 $(1.98,\ 1.46,\ 1.54)$ ⚠️
差 0.0001 $\mathbf{1.8\times10^{-3}}$ 134334 $(\mathbf{1.99,\ -20.96,\ 23.96})$ ❌

看最后一行:真实系数是 $(2, 3, 0)$,算出来是 $(2, -21, 24)$,
完全崩了($-20.96 + 23.96 \approx 3$,两个系数在互相抵消)。

直觉:$x_1$ 和 $x_2$ 几乎一样,所以"$x_1$ 贡献多少、$x_2$ 贡献多少"无法区分,
数据给不出这个信息。任何把 3 分成 $\alpha + \beta = 3$ 的解法,拟合优度都一样。

行列式、条件数在这里的角色,是"这个模型能不能解"的度量。
$\det \to 0$ / 条件数 $\to \infty$ 就是警告信号。

5.2 这对你做研究意味着什么

现象 后果 检查方法
自变量高度相关 系数符号翻转、数值巨大 看条件数 / 相关矩阵
加一个被试再跑 系数剧烈变化 换样本看系数稳不稳
系数大但与理论不符 不是"发现",是共线性假象 别急着解释!

💡 务实建议:跑完回归,一定要看一眼自变量之间的相关系数矩阵。
有两个变量相关超过 0.9?那这俩系数的解释基本不能信。
这是认知科学/心理学论文里最常见的统计问题之一。

⚠️ 诚实说明:
- 上面的数值结果是我实算的(可复现),"行列式为 0 ⇒ 无唯一解"是数学定理。
- 但"共线性在心理学数据里多常见""该怎么处理"是领域问题,
请以统计教材和方法论文献为准。我保证数学,不保证研究规范。


6 数学作业 S8

第 8 题参考代码:

import numpy as np

A = np.array([[1., 1., 1.],
              [2., -1., 1.],
              [1., 2., -1.]])
b = np.array([6., 3., 2.])

D = np.linalg.det(A)
print(f"D = {D:.6f}")

# 克拉默法则:逐列替换
for i, name in enumerate("xyz"):
    Ai = A.copy()          # ← 注意:要 copy!否则会改到 A
    Ai[:, i] = b
    print(f"{name} = {np.linalg.det(Ai) / D:.10f}")

# 更常用的直接解法
print("numpy.linalg.solve:", np.linalg.solve(A, b))

⚠️ 注意 Ai = A.copy(),不拷贝会直接改掉 A,
第二次循环就全错了。这正是阶段 7 学的可变性陷阱,
在这里以最隐蔽的方式出现。


第二部分 · 编程

7 字典:键值对的集合

列表按"位置"取东西(lst[0]);字典按"名字"取东西(d["姓名"])。

person = {"姓名": "张三", "年龄": 18, "专业": "认知科学"}
print(person["姓名"])       # 张三

为什么需要字典:你要取的是"名叫'年龄'的那个",不是"第 3 个"。

7.1 基本操作

操作 例子 说明
取值 d["年龄"] 键不存在 → KeyError
安全取值 d.get("年龄") 不存在返回 None(不报错)
带默认值 d.get("身高", 0) 不存在返回 0
赋值/新增 d["身高"] = 175 有则改,无则加
判断存在 "年龄" in d True / False
删除 d.pop("年龄") 返回被删的值
所有键 d.keys()
所有值 d.values()
所有键值对 d.items() 配合 for k, v in ...
for k, v in person.items():
    print(f"{k} = {v}")

⚠️ d["不存在的键"] vs d.get("不存在的键"),这是最常用的一组区别:
- d[...] 会报 KeyError
- d.get(...) 返回 None

不确定键在不在,就用 .get()。否则程序会因为一个缺失的键而崩掉。

7.2 键必须是"可哈希"的

能当键 不能当键
数字、字符串、元组、None 列表、字典、集合
{(1, 2): "可以"}       # ✓ 元组可哈希
{[1, 2]: "不行"}       # ✗ TypeError: unhashable type: 'list'

💡 为什么:字典靠"哈希"快速查找。可变对象哈希值会变,
一旦变了,字典就找不到它了。所以只允许不可变的东西当键。

这也解释了为什么阶段 7 说"可变对象麻烦",限制无处不在。

7.3 字典保持插入顺序(Python 3.7+)

d = {"b": 1, "a": 2}
print(list(d.keys()))    # ['b', 'a']   ← 按插入顺序,不是字母序

8 集合:只关心"有没有"

集合是无序、不重复的元素集合。

s = {1, 2, 3}
print(s)              # {1, 2, 3}

⚠️ 空集合必须写 set()!
{} 是空字典,不是空集合。

print(type({}))       # <class 'dict'>   ← 注意!
print(type(set()))    # <class 'set'>

8.1 最主要的用途:去重

nums = [1, 1, 2, 2, 3, 3]
print(set(nums))          # {1, 2, 3}
print(list(set(nums)))    # [1, 2, 3]

一行去重。比写循环简单得多。

⚠️ 代价:顺序丢了。集合无序,所以"去重后保持原顺序"要另想办法
(阶段 7 的 remove_duplicates 就是这个)。

8.2 集合运算(数学里的那套)

运算 符号 例子 结果
并集 \| {1,2,3,4} \| {3,4,5,6} {1,2,3,4,5,6}
交集 & {1,2,3,4} & {3,4,5,6} {3,4}
差集 - {1,2,3,4} - {3,4,5,6} {1,2}
对称差 ^ {1,2,3,4} ^ {3,4,5,6} {1,2,5,6}

交集和差集最常用:

被试A = {"张三", "李四", "王五"}
被试B = {"李四", "王五", "赵六"}

print(被试A & 被试B)    # {'李四', '王五'}   都参加过的
print(被试A - 被试B)    # {'张三'}           只 A 有的

💡 查找速度:x in 集合 是接近瞬时的(哈希查找),
而 x in 列表 要逐个扫。数据量大时差距巨大。
不需要顺序、只需要"在不在"时,用集合。


9 🔧 技能卡 8:数据结构怎么选

你现在会三种容器了。遇到问题该用哪个?这张卡给你一个决策清单。

9.1 三选一:一张表

想要什么 用什么 看家本领
按顺序排列、可改 列表 [] 索引、切片、append
按名字取、一一对应 字典 {} d["键"],查找快
只关心有没有、去重 集合 set() 去重、in 快、集合运算

9.2 决策三问

① 我需要"顺序"吗?

② 我需要"名字 → 值"的对应吗?

③ 我需要"快"吗?

操作 列表 字典/集合
按位置取 x[5] 快 —
按名字取 d["k"] — 快
问"在不在" x in c 慢(逐个扫) 快(哈希)
去重 慢 快

9.3 一个真实的选型例子

任务:统计一段文本里每个词出现几次。

思考过程:
- 需要"词 → 次数"的对应 → 字典
- 那"有哪些词"呢?→ 字典的键天然就是

def word_count(text):
    counts = {}
    for w in text.split():
        counts[w] = counts.get(w, 0) + 1   # 不存在当 0,再 +1
    return counts

print(word_count("a b a c a b"))
# {'a': 3, 'b': 2, 'c': 1}

💡 counts.get(w, 0) + 1 这个写法非常常用,
"如果没出现过就当 0,然后加 1"。省掉了 if w in counts: 的分支判断。

再问:如果要"出现过的词有哪些(不重复)"?
→ 集合:set(text.split())。或者 set(counts.keys())。

9.4 别过度优化

⚠️ 可读性优先:数据量小(几千个)时,随便用哪个都行。
先写清楚,真慢了再换。过早优化是万恶之源。

💡 什么时候真的会疼:数据到了十万以上,且在循环里反复查找。
那时候把列表换成集合/字典,速度可能差几百倍。
这是你以后处理实验数据时会真的遇到的问题。


10 🧠 这跟认知科学有什么关系(编程侧)

概念性内容,无法用代码验证,请对照文献。

字典 ↔ 认知建模里的「联想记忆」和「查找表」。

认知科学里有一个经典模型叫联想记忆(associative memory):
记忆是"线索 → 内容"的映射。给它一个线索(键),取回内容(值)。

这和字典是同构的:

字典 联想记忆
d[键] 取回值 给线索,回忆内容
键 → 值的映射 线索 → 记忆的联结
KeyError(键不存在) 遗忘 / 提取失败
d.get(键, 默认值) 提取失败时用默认/猜测填补
键必须唯一 一个线索对应一个记忆

"提取失败"和"没存储"是两回事,这是记忆研究的核心区分之一。
在字典里,它就是 KeyError(根本没有这个键)和值恰好是 None 的区别。
这个概念在编程和认知科学里都需要你分清楚。

集合 ↔ 「特征集合」式的概念表征。

有一类理论认为概念就是一组特征的集合(feature-set / 概念的特征模型):

集合运算 概念表征
交集 $A \cap B$ 两个概念的共同特征("鸟"和"鱼"共有的特征)
并集 $A \cup B$ 上位概念的特征("动物")
差集 $A - B$ 区别性特征("鸟"有而"鱼"没有的)

典型性效应:为什么麻雀比企鹅更像"鸟"?
特征集合模型给出的解释是,麻雀与"鸟"的原型特征集合的交集更大。

⚠️ 重要提醒:
- "特征集合模型"是一个历史上的重要模型,但它有已知的失败案例
(典型性效应、组合性、模糊边界都难解释),后来被原型理论、样例理论等取代或补充。
- 这一节是让你看到"数学结构在认知建模里真的被用到",不是让你把它当结论。
请以文献为准。


11 编程作业 S8

第 3 题参考写法:

def invert(d):
    result = {}
    for k, v in d.items():
        result[v] = k          # ⚠️ 值重复时,后面的会覆盖前面的
    return result

print(invert({"a": 1, "b": 2}))                  # {1: 'a', 2: 'b'}
print(invert({"a": 1, "b": 1}))                  # {1: 'b'}  ← 1 被覆盖了!

⚠️ 这就是"值必须唯一"才能安全反转。
想保留所有,就得把值存成列表:{1: ['a', 'b']}。
写代码前先想清楚"重复会发生什么",这就是边界思维。

第 7 题参考写法:

def merge_counts(c1, c2):
    result = c1.copy()                 # ← 先拷贝,别改传入的字典(阶段 7 的教训)
    for k, v in c2.items():
        result[k] = result.get(k, 0) + v
    return result

a = {"x": 1, "y": 2}
b = {"y": 3, "z": 1}
print(merge_counts(a, b))    # {'x': 1, 'y': 5, 'z': 1}
print(a)                     # {'x': 1, 'y': 2}   ← 原字典没被改 ✓

assert merge_counts({"a": 1}, {}) == {"a": 1}
assert merge_counts({}, {"a": 1}) == {"a": 1}
print("检查用例通过")

第 6 题答案:

d1 = {"a": 1}
d2 = d1          # ⚠️ 别名!不是拷贝
d2["b"] = 2
print(d1)        # {'a': 1, 'b': 2}   ← d1 也被改了

和 Ai = A.copy() 是同一个病:d2 = d1 只是又贴了一个标签,
两个名字指向同一个字典。改一个,另一个也变。
正确写法:d2 = d1.copy()。


本阶段自评

  1. 数学:二阶行列式怎么算?三阶的萨吕斯法则有几项?
  2. 数学:萨吕斯法则能用于四阶吗?为什么?
  3. 数学:哪条性质让你"不算就知道行列式是 0"?
  4. 数学:计算机算行列式实际用哪条性质?为什么是它?
  5. 数学:克拉默法则的三个局限分别是什么?
  6. 数学:为什么"有公式"不等于"该用公式"?举本阶段的例子。
  7. 编程:d["键"] 和 d.get("键") 有什么区别?什么时候用哪个?
  8. 编程:为什么列表不能当字典的键?这和阶段 7 的"可变"有什么关系?
  9. 编程:空集合怎么表示?为什么 {} 不行?
  10. 技能:三选一决策清单,列表/字典/集合各自适合什么场景?
  11. 连接:为什么自变量高度相关会让回归系数"崩掉"?$\det(X^TX)$ 在这里是什么角色?

全部答得上 → 大一上阶段 1–8 完成,进阶段 9。

最后更新:2026-09-26