正交表构造方法PPT课件:有限域、贪心算法与Python批量生成

正交表构造方法PPT课件:有限域、贪心算法与Python批量生成 简介「正交表构造方法PPT课件」面向统计学、质量管理、工程优化及科研实验设计方向的初学者与实务工作者系统梳理正交试验设计的核心概念与正交表构造逻辑。课件从析因设计实验次数过多的问题切入说明正交试验如何借助「均匀分散、整齐可比」的原则从全面试验中挑选代表性组合进而讲解Ln(ji)符号中行数、位级数与列数的含义并以L9(3^3)、L18(3^7)、L8(4×2^4)等典型表为例辨析等水平表与混合型正交表的差异。同时结合三因素三水平实例对比全面实验法与正交表安排实验的工作量差异帮助读者掌握根据因素与水平数选表、安排试验并分析因素影响的基本流程。资源包共1个pptx文件约440KB页面按概念、符号、结构、正交性与应用逐步展开适合课堂讲授或自学浏览。目前已有79人学习。1. 正交表构造方法PPT课件卡人的从来不是排版「正交表构造方法PPT课件.pptx」这个文件名通常出现在两个场景里测试团队要做组合用例裁剪的内部培训质量工程岗给新人解释“7 个参数各 3 个取值为什么不用跑 2187 次”。真动手做这份课件的人会发现难点不在母版和配色——排版半小时就能搞定卡住的是表本身这张表从哪来、正交性凭什么成立、混合水平的列怎么拆、现场演示时能不能一键验证。把这件事讲透背后至少要跑通三件事用有限域或者贪心算法把表算出来用脚本当场校验正交性再用 python-pptx 批量生成表格页和公式页。读者如果只是要一份能用的课件可以直接抄第 4 章的脚本如果要讲清“为什么 L9 是 9 行而不是 8 行”第 2、3 章的推导是必须补的。这份课件真正值钱的地方是它把统计试验设计和组合测试两个领域的共同底座摊开给人看。2. 正交表的结构与构造方法选型L_n(m^k)、强度与正交性判据2.1 正交表的三要素行数、水平数、列数与 L_n(m^k) 记法正交表的标准写法是 L_n(m^k)三个数字各管一件事n 是行数也就是实际要跑的试验次数k 是列数代表最多能安排多少个因素m 是每一列的水平数也就是单个因素有几个取值。L9(3^4) 读作“9 次试验、4 个因素、每因素 3 个水平”它替代的是 3^4 81 次全组合。做课件时容易讲错的一点是行数从哪来。对称表所有列水平数相同里n m² 时最多只能放 m1 列这不是巧合L4(2^3)、L9(3^4)、L16(4^5)、L25(5^6) 全部满足 k m1它正是有限域构造的直接产物。列数需求超过 m1 时就得换更大的表比如要 7 个 2 水平因素只能上 L8(2^7) 或 L16(2^15)行数从 4 跳到 8 再到 16。因素数、列数、行数之间的这种“跳档”关系是必须讲的一课否则听众会以为行数可以随便定。非对称表另算L18(2^1×3^7) 是经典例子18 行1 个 2 水平列加 7 个 3 水平列。它的 18 不是任何水平数的平方由正交拉丁方拼合而成正交性要按最小公倍数 6 来核对——2 水平与 3 水平两列的组合共 6 种每种在 18 行里出现 3 次。2.2 正交性判据与强度 t什么时候 L18 比 L16 更合适严格正交的判据可以写成一句话任意两列的水平组合出现次数完全相同都等于 n/m²混合表按两列水平数之积算。这个条件是“强度 2”的定义。把定义推广一步就是强度 t任意 t 列的所有水平组合出现次数相等t3 的表能覆盖三因素之间的交互作用但行数会明显上涨——3 水平、4 因素的强度 3 表最少要 27 行。工程上还有一类更宽松的表叫覆盖数组 CA(N; t, k, v)只要求任意 t 列的组合至少出现一次不要求等频。行数能压得比严格正交表更少代价是失去方差分析所需的均衡性。这个区别在课件里必须标清楚指标严格正交表覆盖数组组合频次每对组合出现次数完全相同至少出现一次行数固定多为 m² 或其倍数不固定追求最小能否做方差分析能不能只用于组合覆盖典型工具标准正交表手册PICT、贪心算法脚本适用场景试验设计、参数寻优软件组合测试、用例裁剪回到 L18 与 L16 的选择因素里有 2 水平和 3 水平混搭又不想为凑齐 4 水平做拟水平时L18 是更省的选择如果所有因素都能统一到 2 水平L16 更整齐后续分析也简单。2.3 四种构造方法选型对比查表、有限域、Hadamard、贪心覆盖真正落地时只有四条路课件里给一张对比表比讲十页公式有用方法适用条件行数混合水平支持实现成本查标准表因素数与水平数匹配现成表固定需直接选混合表最低有限域 GF(q)q 为素数或素数幂q²要靠并列/拟水平中等Hadamard 矩阵全部为 2 水平n 2^j2n不支持中等贪心覆盖任意水平组合近似最小天然支持较高要调参不管走哪条路交付前都要过一遍校验。这段校验脚本可以直接放进课件当现场演示import itertools import numpy as np def check_orthogonal(rows, strength2, tol1e-9): 校验强度为 strength 的正交性返回 (是否通过, 明细列表) A np.asarray(rows) # 每行是一次试验每列是一个因素 n, k A.shape ok, report True, [] for cols in itertools.combinations(range(k), strength): sub A[:, cols] # 取出 t 列 counts {} for row in sub: counts[tuple(row)] counts.get(tuple(row), 0) 1 freq set(counts.values()) # 各组合的频次应当只有一个值 expect n / len(counts) # 混合水平下 len(counts) 自动等于水平数之积 if len(freq) ! 1 or abs(next(iter(freq)) - expect) tol: ok False report.append((cols, sorted(freq), expect)) return ok, report ok, detail check_orthogonal([[0,0,0],[0,1,1],[0,2,2], [1,0,1],[1,1,2],[1,2,0], [2,0,2],[2,1,0],[2,2,1]]) print(ok) # True这就是 L9(3^4) 的其中三列逻辑上这段代码只做两件事枚举所有 t 列组合统计每种水平组合出现的次数再检查这些次数是否整齐。strength改成 3 就变成三列校验expect n / len(counts)这个写法对混合水平表同样成立因为笛卡尔积的长度就是水平数之积不需要为 L18 单独写分支。注意n 大于 100 时这段统计会变慢实际项目里我一般只抽样校验若干列组合或者把组合键转成整数编码后用 numpy 的 bincount 统计。3. 用 Python 实现正交表构造从有限域到混合水平3.1 有限域 GF(p) 构造 L_{p²}(p^{p1}) 的最小实现对任意素数 p标准构造法只需要十几行代码。核心思路是把行号 t 写成二元组 (a, b)两者都取自 GF(p)列则取 a、b 以及全部 a λbλ 遍历 GF(p)def oa_from_prime_field(p): 构造 L_{p^2}(p^{p1})p 必须是素数 assert p 1 and all(p % d for d in range(2, int(p ** 0.5) 1)), p 必须为素数 table [] for a in range(p): for b in range(p): # 前两列固定取 a、b其余 p 列取 a λb mod p row [a, b] [(a lam * b) % p for lam in range(p)] table.append(row) return table t oa_from_prime_field(3) print(len(t), len(t[0])) # 9 4即 L9(3^4)为什么这样构造出来一定是正交表任取两列它们的取值分别是 a λ₁b 和 a λ₂b。当 λ₁ ≠ λ₂ 时(λ₁ - λ₂) 在 GF(p) 上可逆给定任意一对目标值都能唯一解出 (a, b)所以每种组合恰好出现一次。λ₁ λ₂ 时两列相同组合自然均匀。这就是课件里“为什么”部分唯一需要讲的代数理由比画图直观得多。换 p 值就能拿到不同规格p2 得 L4(2^3)p3 得 L9(3^4)p5 得 L25(5^6)。但 4 水平拿不到因为 4 不是素数。要构造 L16(4^5) 必须上素数幂 GF(4)元素用二进制表示加法即按位异或乘法查对数表LOG [None, 0, 1, 2] # LOG[1]0, LOG[2]1, LOG[3]2 EXP [1, 2, 3] # EXP[0]1, EXP[1]2, EXP[2]3 def gf4_add(a, b): return a ^ b # GF(4) 加法等价于按位异或 def gf4_mul(a, b): if a 0 or b 0: return 0 return EXP[(LOG[a] LOG[b]) % 3] # 乘法走对数表模 3 是因为乘法群阶为 3把 3.1 里的% p换成gf4_add和gf4_mul同一套循环就能生成 L16(4^5)。这一步在课件里值得单独一页它把“水平数必须是素数幂”这个限制从口诀变成了可运行的事实。3.2 贪心构造混合水平正交表逐行扩展的完整脚本实际项目里因素水平数很少整齐[2,3,3,4,5] 这种组合查表查不到有限域也套不上只能走贪心。做法是一行一行加每加一行都挑“新覆盖组合数最多”的那一行import itertools, random def greedy_covering_array(factors, strength2, seed42, tries200): factors: 每个因素的水平数列表返回覆盖所有 t 列组合的行集合 rng random.Random(seed) combos list(itertools.combinations(range(len(factors)), strength)) uncovered set() for c in combos: for vals in itertools.product(*[range(factors[i]) for i in c]): uncovered.add((c, vals)) # 待覆盖的 (列组合, 取值) 全集 rows [] while uncovered: best_row, best_gain None, -1 for _ in range(tries): # 随机撒 tries 个候选行 row [rng.randrange(m) for m in factors] gain sum(1 for (c, v) in uncovered if tuple(row[i] for i in c) v) if gain best_gain: best_gain, best_row gain, row rows.append(best_row) for (c, v) in list(uncovered): # 把这一行覆盖掉的组合移除 if tuple(best_row[i] for i in c) v: uncovered.discard((c, v)) return rows t greedy_covering_array([3, 3, 3, 3]) print(len(t), len(t[0])) # 大约 9~12 行全组合是 81 行factors的顺序就是列的语义顺序值是每列的水平数混合水平直接写 [2,3,3,4,5] 即可。tries是每行撒的候选数直接决定结果质量和耗时因素少时 60 就够因素上到十几个、水平数到 5 时建议提到 300 以上否则很容易被局部最优困住多出三成行数。seed固定是为了让课件现场的演示结果可复现——这一点比追求绝对最小行数更重要听众要能自己跑出同一个数字。3.3 构造结果的校验、截断与常见错误生成完必须校验三个最容易翻车的地方第一行数与水平组合的整除关系。混合水平表要检查任意两列的最小公倍数 L lcm(m_i, m_j) 是否整除 n不整除就说明它不是严格正交表只能当覆盖数组标注。L18 之所以成立是因为 2 和 3 的 lcm 是 618 能被 6 整除。第二水平编码混用。有的表用 0 起始有的用 1 起始同一张表里混着来会直接破坏统计结果也会让check_orthogonal报出假失败。我一般统一成 0 起始展示给业务方的表格页再加一列序号从 1 开始。第三截断列的合法性。L16(2^15) 只取前 7 列做 7 因素完全没问题但反过来把 4 水平列强行当 2 水平列用拟水平法会破坏该列与其他列的正交性必须重新跑一遍校验脚本通不过就不能写进课件当结论。4. 把正交表构造方法做成 PPT 课件的工程化流程4.1 课件页面结构公式页、表页、对比页的比例与信息密度我一般把 2430 页的课件按 1:1:1 分三段前段讲问题组合爆炸有多可怕用具体数字例如 7 因素 3 水平 2187 行 vs L27 的 27 行中段讲构造公式 可运行代码 逐步校验后段讲落地工具选型、团队协作、常见误用。文字页控制在总页数的两成以内其余全是表、公式和代码截图。信息密度是翻车重灾区。一张完整 L27(3^13) 有 27 行 13 列塞进 16:9 一页会把字号压到 8pt 以下投影时最后一排根本看不清。常见做法是拆成两页或者只展示前 4 列并在备注里说明截断。表格页的硬指标最小字号不低于 12pt单页表格行数不超过 20 行。4.2 用 python-pptx 批量生成正交表页面手画 20 页表格没人愿意干第二次用脚本生成才是正解from pptx import Presentation from pptx.util import Inches, Pt from pptx.dml.color import RGBColor prs Presentation() prs.slide_width, prs.slide_height Inches(13.333), Inches(7.5) # 16:9 BLANK prs.slide_layouts[6] # 空白版式 def add_oa_slide(title, table, note): slide prs.slides.add_slide(BLANK) tb slide.shapes.add_textbox(Inches(0.6), Inches(0.35), Inches(12), Inches(0.8)) tb.text_frame.text title tb.text_frame.paragraphs[0].font.size Pt(28) tb.text_frame.paragraphs[0].font.bold True rows, cols len(table), len(table[0]) shape slide.shapes.add_table(rows, cols, Inches(0.6), Inches(1.4), Inches(12.1), Inches(5.4)) tbl shape.table size Pt(14) if rows 20 else Pt(9) # 行数多就降字号别让表格溢出 for r, row in enumerate(table): for c, val in enumerate(row): cell tbl.cell(r, c) cell.text str(val) for p in cell.text_frame.paragraphs: p.font.size size if r 0: # 表头反色 cell.fill.solid() cell.fill.fore_color.rgb RGBColor(0x1F, 0x4E, 0x79) for p in cell.text_frame.paragraphs: p.font.color.rgb RGBColor(0xFF, 0xFF, 0xFF) if note: nb slide.shapes.add_textbox(Inches(0.6), Inches(6.9), Inches(12), Inches(0.5)) nb.text_frame.text note return slide oa oa_from_prime_field(3) header [[No.] [fF{i1} for i in range(len(oa[0]))]] add_oa_slide(L9(3^4)任意两列的组合各出现 1 次, header [[i 1] r for i, r in enumerate(oa)], 9 行替代 81 行全组合压缩率 88.9%) prs.save(正交表构造方法.pptx)参数上要注意三点。add_table用的是真实表格对象而不是图片好处是讲课时可以现场改某个格子的值重算。尺寸单位统一用Inches系数按 13.333 宽换算直接抄不会错位。字号我用行数做条件判断rows 20用 14pt否则用 9pt——但 9pt 已经接近投影极限更好的办法是拆页而不是缩字号。提示python-pptx 里设置行高row.height经常被内容撑开覆盖别依赖它做垂直居中宁可让表格整体上移、底部留白。4.3 公式渲染与图片嵌入matplotlib mathtext 的三个坑正交表课件绕不开公式python-pptx 本身不支持公式对象通用做法是用 matplotlib 把公式渲染成透明 PNG 再插进去import matplotlib matplotlib.use(Agg) # 无界面环境必须指定后端否则报错 import matplotlib.pyplot as plt def render_formula(tex, out_png, fontsize30, color#1F4E79): fig plt.figure(figsize(0.01, 0.01)) fig.text(0, 0, f${tex}$, fontsizefontsize, colorcolor) fig.savefig(out_png, dpi300, bbox_inchestight, transparentTrue, pad_inches0.05) plt.close(fig) render_formula(rn m^2,\quad k m 1, f1.png) render_formula(r\sum_{j1}^{m} c_{ij} \frac{n}{m}, f2.png)第一个坑是 mathtext 不是完整 LaTeX\begin{array}、大部分\text{}用法都不支持矩阵只能改用\matrix或干脆画成表格页。第二个坑是bbox_inchestight和透明背景要一起用只设透明不设 tight公式周围会留一大片空白插进 PPT 后对不齐。第三个坑是体积300dpi 的图片单页超过 6 张pptx 很容易冲到几十 MB公式改用 200dpi 在投影上肉眼看不出差别。插入时按顺序往下排就行def add_formula_slide(title, png_list): slide prs.slides.add_slide(BLANK) slide.shapes.add_textbox(Inches(0.6), Inches(0.35), Inches(12), Inches(0.8)) \ .text_frame.text title top Inches(1.6) for png in png_list: slide.shapes.add_picture(png, Inches(1.2), top, heightInches(0.9)) top Inches(1.2) # 固定步长排布避免公式互相压叠 return slide4.4 打包前的自检清单课件做完别急着发出去下面这几项每一条我都踩过检查项建议阈值不达标会怎样单文件体积小于 20 MB邮件和 IM 直接传不动中文字体等线、微软雅黑等通用字体换机器变宋体公式和表格错位表格最小字号不低于 12 pt投影最后一排看不清公式图片分辨率200300 dpi全屏放大后边缘发虚幻灯片尺寸13.333 × 7.5 英寸16:9 投影两侧出现黑边总页数2030 页90 分钟根本讲不完体积超标时优先压公式图片而不是删表格——表格是这份课件的核心资产公式可以精简到每页最多三个。5. 课件里的正交表怎么讲透三个必调参数与验证技巧5.1 强度 t 与随机候选数两个直接决定行数的参数现场演示最有冲击力的一幕是把强度从 2 调到 3。同样是 4 个 3 水平因素强度 2 的贪心结果通常 912 行强度 3 直接跳到 27 行左右正好等于 m^t 的下界。改一个参数、行数翻三倍这个对比比任何公式都更能说明“交互作用是要花钱买的”。第二个参数是贪心的随机候选数tries。单次贪心不保证最优常规做法是换几个随机种子跑取行数最少的那次for seed in (1, 7, 42, 2024): rows greedy_covering_array([3] * 4, strength2, seedseed, tries300) print(seed, len(rows))我把这段做成课件里的一个代码页让听众自己改tries观察行数波动。经验值46 个因素取 100200 次候选足够稳定因素数超过 10 个、水平数超过 4 时300500 次起步否则同一份模型不同次运行的行数能差 30%讲课时前后两页数字对不上就很尴尬。5.2 混合水平拆分的验证技巧混合水平是课件里最容易讲糊的部分两种拆分法必须区分清楚。拟水平法是把 3 水平列重复一个取值凑成 4 水平好处是能塞进 L16 这类整齐的表代价是该列与其他列的正交性被破坏拆完必须重新跑check_orthogonal通不过就只能当覆盖数组用。并列法是把 L16(4^5) 里的一列 4 水平按 (0,1) 与 (2,3) 拆成两列 2 水平行数不变但拆出来的两列完全相关不能同时用来估计独立效应——课件里如果后面要讲方差分析这一条必须用红字标出来。一个稳妥的验证套路是两步走先用check_orthogonal检查频次集合大小是否为 1再用整除规则复核混合水平表——计算任意两列水平数的最小公倍数 L检查 n % L 是否为 0不为 0 就说明这张表天生做不到严格正交只能在课件里标注为覆盖数组。把这两步封成一个validate_oa(rows)函数第 4 章的脚本每次生成完表格页顺手调用一次课件的每一张表都能在讲台上按一次回车证明它对不对不用背结论。本文还有配套的精品资源点击获取