正交表
正交表(orthogonal array)是一种按指定强度精确均衡因素组合的表格。把每次试验排成一行、每个因素排成一列,在任意指定数量的列中,各种水平组合都出现同样多次。这种均衡可用于试验设计,也能用来构造具有低阶独立性的有限随机样本。
例如,下表每列取零、一两个水平: 任选两列, 都恰出现一次。但三列只出现四种组合,而非全部八种;两两均衡与三因素均衡是不同要求。
参数与强度
本文用 表示一个 表,元素取自 个水平,满足 、。对任意 列,全部 种有序水平组合都恰出现 次。其中 且 为正整数,称为指数。各文献参数顺序、行列约定有所不同,比较设计时应先核对“试验是一行还是一列”。[1]
上面的表是 ,指数一。固定前两列,它们已经列出全部二位组合;对第一、三列及第二、三列逐一计数也得到同样结果。第三列实际是前两列的异或,这给出一个可直接复核的构造。
低阶边缘仍然均衡
若表的强度为 ,则任取 列及一种固定的 元组合,也会出现 次。证明。 将这 列扩充成某 列。其余 列共有 种组合,每种与固定的 元组合配对后都出现 次,逐项相加即可。
所以强度二自动使每个单因素均衡,反过来却不成立。两行 与 的每列都零一各一次,但任意两列只有 ,缺少另外两种组合。
两两独立而不相互独立
从正交表的 行中等概率随机选一行,把第 列的值记为随机变量 。任取 列,其某种组合出现概率为 各列单独均匀取 个水平,联合概率等于各自概率乘积,因此任意不超过 个不同因素相互独立。这是有限表格中的精确概率陈述,不需要近似抽样。
在四行三列表中,。因此任意两变量独立,但给定前两变量就完全确定第三变量。例如 而三列若相互独立,该概率应为 。正交强度的意义正是明确可保证的联合阶数。
二水平编码与正交性
把零编码为 、一编码为 ,将上述表的三列记为 ,再增加全一截距列 。每个因素均衡,故 ;每对因素四种组合各一次,所以其乘积有两次 、两次 ,从而 。
各列平方长度都是四。令 ,便得到 这说明在只含截距与三个主效应的线性模型中,各列在代数上正交。它不意味着所有交互作用都能单独估计。本例在负一、一编码下 (右侧逐元素相乘),第三主效应列与前两因素交互作用列只差符号,二者在该表上混杂,无法同时辨认。
变式。 能否只用四次试验,给四个二水平因素构造强度二正交表?若能,其四个均衡编码列加截距列会是 中五个非零且两两正交的向量。非零正交向量必线性无关,而四维空间最多有四个,矛盾。因此不能;单有整除条件 并不足以保证任意列数都可实现。
拉丁方与三因素构造
对一个 阶拉丁方,逐格记录“行号、列号、符号”,得到 行、三列的表。行号与列号的组合自然各出现一次;固定行号和符号,由拉丁性质唯一确定列号;固定列号和符号也唯一确定行号。故得到 。
反过来,若有指数一的这类表,以前两列作为行号、列号,第三列填符号,二列投影均衡恰好保证每行每列不重复。这个双向构造把“一个方阵”与“一张试验清单”对应起来,不能把两种表格的行列数直接混写。
定义检验程序
下面按定义枚举列组合、计数每种投影。输入为至少一行等长试验,每个水平必须是 的整数;不修改原表。
from collections import Counter
from itertools import combinations
def orthogonal_index(array, levels, strength):
rows = [tuple(row) for row in array]
if type(levels) is not int or levels < 2 or not rows:
raise ValueError("Need rows and at least two levels")
width = len(rows[0])
if (type(strength) is not int or not 1 <= strength <= width
or any(len(row) != width for row in rows)):
raise ValueError("Invalid dimensions or strength")
if any(type(x) is not int or not 0 <= x < levels
for row in rows for x in row):
raise ValueError("Invalid level")
target, remainder = divmod(len(rows), levels ** strength)
if remainder or target == 0:
return None
for columns in combinations(range(width), strength):
counts = Counter(tuple(row[j] for j in columns) for row in rows)
if len(counts) != levels ** strength:
return None
if any(count != target for count in counts.values()):
return None
return target
print(orthogonal_index([[0, 0, 0], [0, 1, 1],
[1, 0, 1], [1, 1, 0]], 2, 2))
print(orthogonal_index([[0, 0, 0], [1, 1, 1]], 2, 2))
# 1
# None
只要每组列投影有全部 种不同组合、每种频数都为同一正整数,便恰好满足定义;任何缺失或频数不等都使程序返回 None。按散列表平均时间计,检查所有投影需 次基本操作;复制输入需 空间,单次投影计数至多保存 个长度 的键。
覆盖数组只要求每种指定组合至少出现一次,不要求频数相等。在测试问题中,这种放宽可允许更多因素使用较少的试验行;是否需要均衡,应由试验分析目标而非表名决定。
参考资料
- ↑ Andries E. Brouwer:Orthogonal Arrays,Eindhoven University of Technology。该页使用因素为行、试验为列的转置约定 ;本文使用 行试验、 列因素,并保留相同的等频定义。访问日期:2026年10月25日。