人类对随机的感觉一直有偏差,例如我们不喜欢单一而喜欢交替。举个例子:抛硬币的时候,在连续六个 H 之后我们会倾向于下一个一定是 T;当我们看到 HHHHHH 这种序列,我们会认为其不如 HTHTTH 随机;真正的随机实际上是只有在大数范围内才能做到“雨露均沾”,但我们对小范围内的抽取仍然希望它能够做到“雨露均沾”。因此所谓的“公平抽取”实际上是伪随机,需要我们通过算法去拟合人们对随机的欲望和期待。
Warning
接下来的内容会涉及长篇累牍的数学解释和数学符号以及数学公式。强烈建议直接去阅读源代码 而不是在这里生啃。接下来的内容是给数学 M 和不愿意认真读代码的人准备的。
众所周知,这类算法,抽学生肯定是要有一个权重。那么在本算法中一个学生的总公式是这样的:
$$
w_s = {\big[\pi_s(M+h_s)-c_s]}^+ \cdot \big[\pi_{x(s)}^X(M+gK)-c_{x(s)}^X]^+ $$
$$
p_s=(1-\varepsilon),\frac{w_s}{\sum_j w_j}+\frac{\varepsilon}{|\mathcal P|}
$$
候选池 $\mathcal P$ = 在场且未被屏蔽且 $c_s<\text{Cap}_s$ 的人;$\pi_s\propto$ 倍率;$M$、$c^X$ 都只在池内统计。$\sum w=0$ 时在池内等权。
可供外部配置的参数有:
参数
默认值
量纲
$h_s$ (个人视野 × 池大小)
$2.0$
次数
$g$ (性别视野 × 批量 $K$ )
$0.8$
次数
$\varepsilon$ (保底份额)
$0.10$
比例
$\text{Cap}_s$
随你便,大于0就行
次数
真可怕!但是没关系,让我们来一点点的解析它。
从前面我说的可以知道,人类对随机的“感觉”实际上是这几个东西:
比例公平:废话。记每个人应得的概率为$\pi_s$。
刺激感:不要让人觉得自己永远不会被点到,“炮弹永远不会落在上一个弹坑里”是永远的伪命题
感知随机:短期节奏像随机但略好于随机,不会出现一直男生或者一直女生,也没有倒霉蛋被连点六次(这事情真的发生过)
但是请注意:第一条是约束,而剩下两条是手感 。权重公式优化的是手感上的问题而不是约束的问题。
前文所说,一个硬币扔了 49 次正面,我们会期待它是反面:这就是最经典的“赌徒谬误”之一。这反映出的其实是我们对随机这件事情的错误认识:我们认为随机数发生器应该有“记忆”,能记住谁多谁少。
那么,为了拟合,我们的公式一定要有记忆。记什么呢?什么最好记?记哪些指标最省事?
答案是:谁被抽中了几次 。课堂需要有记忆。除非你被老师针对了或者你这节课太闹腾了,老师也不喜欢反反复复点同一个人起来(除非只有一个人能回答,这是后话),那谁记“我 5min 前点了 xxx 和 yyy”,你只需要大概知道 xxx 和 yyy 各被点了多少次,这就够了。记这个数为 $c_s$ ,一节课所有人被点到的次数为 $M,M=\sum_s{c_s}$ 。
既然都要记着次数了,被点到多的人(相对较多)的人肯定爆率小对吧,那把它变成数学公式,最自然的方式就是:$\pi_sM$,你就应该被摊上这么多次;但是这没有冗余啊…… Airbus A320 的(大致)失速速度 $V_{s}$ 是 128kt, 但这并不意味着你到 127.9kt 就一定会失速(实际上有 Alpha Floor, 你敢这么干给你按死,回家写报告去吧)所以为了冗余:我们引入“视野大小” $H$ ,把应得改成“面向未来的 $H$ 次后的应得”。这就合理多了。记一个人为 $s$ ,其应得份额$D_s$为:
$$
D_s=\pi_s\big(M+H\big)
$$
在本算法中,我们将这个“偏离”说成“欠账”。原因很简单,我缺钱易于理解。
欠账就是应得减已得,负数归零(为什么?你怎么做到欠别人负数块钱的,教我), 记max(any,0)为$[\cdot]^+$(这个cdot这个点就是任意东西的意思):
$$
r_s=\big[D_s-c_s\big]^+=\big[\pi_s(M+H)-c_s\big]^+
$$
不过这个负数截断也可以带来一个新的作用:记 $N$ 为可以被选中的学生数量,任何 $s$ 的上偏离 $c_s-M/N$ 不可能超过 $H/N$ ,不会有欧皇也不会有非酋,多是一件美事。
设$p_s$为每位学生应得的概率:每一次抽取的时候,不管这次抽中了谁,$M$ 都会加 1,所以 $s$ 的应得份额 $\pi_s(M+H)$ 会上涨 $\pi_s$ 。
如果这次抽中的恰好是 $s$ ,$c_s$ 加 1,欠账再多跌 1。也就是说:
没被抽中(概率 $1-p_s$ ):欠账变化为 $+\pi_s$
被抽中(概率 $p_s$ ):欠账变化为 $+\pi_s - 1$
取期望:欠账的期望变化 = $\pi_s − p_s$ 。这一步是精确的,不是什么近似。
用数字感受一下。班里 40 人均分时 $\pi_s=1/40$ 。没被点中时欠账涨 0.025;被点中时欠账跌 $0.025-1=-0.975$ 。所以只有在 $p_s=0.025$ 时,两个方向恰好互相抵消。
欠账是个有界的量——它最多涨到 $H$ 附近(因为总和恒等于 $H$ )。一个有界的量在长期里,期望变化必须为零,否则会一直涨或一直跌。
所以系统要安定下来,只有一个条件:
$$
\boxed{p_s=\pi_s}
$$
不仅如此,接下来各位看官请看:假设随机数引擎是一个能均匀的产生随机数的引擎。那么学生 $s$ 被抽中的概率是:
$$
p_s=(1-\varepsilon)\frac{w_s}{\sum_j w_j}+\frac{\varepsilon}{N}
$$
其中,$\varepsilon$是保底份额,一个 0 ~ 1 的小数,我们稍后再讲。
再代入稳态条件 $p_s=\pi_s$ ,用七年级(还是八年级?)教的“等式的性质”,可以见得:
$$
\frac{w_s}{\sum_j w_j}=\frac{\pi_s-\varepsilon/N}{1-\varepsilon}=\pi_s
$$
它约等利用了 $\sum_j\pi_j=1$ ,而$\dfrac{\pi_s-\varepsilon/N}{1-\varepsilon}$ 不是什么新概念,它就是 $\bold{\pi_s}$ 。保底项被负反馈完整吃掉了 。
注:我推导的时候的表情大概就是当你在某道高深的几何题挖空心思设了一个方程然后解出来x=x
何意味耶?实际上这个推论对某些喜欢内定的关系户有点用:
第一,静态偏置无效。如果你给某人的权重加一笔固定加成,ta 的 $p_s$ 会短期冒头,被抽次数随之涨得更快,欠账加速回落,直到 $p_s$ 重新降回 $\pi_s$ 。
第二,倍率真实生效。 $\pi_s$ 是这个系统的均衡点。把 $\pi_s$ 调大一倍,欠账会以双倍的速率恢复,稳态时的被抽概率也随之翻倍。(公报私仇的来了)
说白了:假设某个时刻 $p_s$ 略高于 $\pi_s$ 。那么期望变化为负:欠账会缩。欠账一缩,权重就跌,$p_s$ 跟着降——直到退回 $\pi_s$ 为止。反之亦然,被抽少了欠账会涨、把概率抬回来。(像不像你买的某些股票……实际上自然的市场经济的规律类似,数学真是奇妙XD)
金将军有云:随机算法一定要随机
事与愿违。实际上通过操纵一些参数我们可以操纵“随机”的程度,或说节奏:
把偏离量 $\xi_s=c_s-M/N$ 看成在 $[-h,h]$ 区间内的有界扩散。漂移强度大致是 $(1-\varepsilon)/(Nh)$ 向零拉(因为欠账越大越易被抽),扩散强度由抽样噪声给出;这里的小h泛指任何“视野”。
一次启发式推导(把它当 OU 过程近似)给出稳态方差:
$$
\operatorname{Var}(\xi_s)\approx\frac{h}{2(1-\varepsilon)}
$$
这是唯一无法从守恒量直接推出、需要模拟验证的关系式($h=2,\varepsilon=0.1$ 时理论 1.111,实测 1.065,误差 4%),但至少看起来他长得像正解:节奏自由度与 $H$ 成正比、与保底成反比。
$h\to\infty$ 时无约束,等价于泊松抽样(i.i.d.);$h\to0^+$ 时偏离不能超过 0,化成严格轮转。中间是一个连续可调的滑杆。
记一个学生的性别为$x(s)$,性别账本和个人账本完全同构,只是把 $\pi_s$ 换成 $\pi^X_j=\sum_{s,:,x(s)=j}\pi_s$ ,把 $H$ 换成 $g\cdot K$ ($g$ 为系数,$K$ 为批量)。
关键差异是 $g\cdot K$ 极小(约 1 次量级),所以性别欠账总和只有 $\approx g\cdot K/2$ 次——每类最多「领先」约 $gK/2$ ,多抽一次立刻欠账归零。
当 $gK<1$ 时进入一个可解析的角落:领先方的欠账必然归零,权重层只剩异性别。此时交替率可以精确求解。
但这带来一个新的问题:设保底份额为 $\varepsilon$ 。一次抽取走「权重层」的概率是 $1-\varepsilon$ ,而权重层此时必然给出与上次不同的性别(因为领先方没权重)。走「保底」的概率是 $\varepsilon$ ,而保底全等,给出异/同性别的概率各 1/2。
能不能不交替?只在这一种情况下有:性别账里领先方并未归零的特殊态。但是——需要追踪马尔可夫链。繁琐的事情来了:(下面我允许你们跳过几行)
设 $u$ 为两性计数差的一半($u\in{0,\pm\frac{1}{2},\pm1,\dots}$)。在饱和条件下每抽一次 $u\to u\pm\frac{1}{2}$ ,且折扣参数 $q=\varepsilon/2$ 。平稳分布为 $\pi_0=\frac{1-2q}{2(1-q)}$ ,向前/向后分裂后:
$P(A)=\frac{\pi_0}{2}+\mathbb{P}(\text{方向反转})=\frac{1}{2}+\frac{(1-2q)^2}{4(1-q)}=\boxed{\frac{1}{2}+\frac{(1-\varepsilon)^2}{2(2-\varepsilon)}}$
验证:$\varepsilon=0\to 0.75$,$\varepsilon=0.1\to0.7132$(实测 0.7123,误差 0.0009),$\varepsilon=1\to0.5$(纯随机下限)。这个式子是整条公式里唯一保证收获到漂亮闭式的地方。(大喜)
而根据可靠文献,(我忘了引用放哪了)人类对“随机”的概念中,交替率峰值就是0.7。简单带进去解一下:$(1-\varepsilon)^2=2(2-\varepsilon)(0.70-0.5)$ 解得 $\varepsilon\approx0.147$ 。各位应该是知道有的调参了。
$$
\boxed{w_s=r_s\cdot r^X_{x(s)}}
$$
为何相乘?假设用加法:$w_s\propto r_s+r^X_{x(s)}$。个人欠账再大,最多把权重推到 $r_\text{max}$ ,而加性性别项只能再叠加常数量的偏移——无法把领先性别压到一个合理范围内。
乘法正是我们想要的。两个因子之一归零,权重即归零——这是一次“与”:个人够资格且性别够资格,你才能上前线。这就是为什么公式里没有一个加号。
小组呢?各位,老师们分组的时候不会一个组只剩下你一个吧。既然人与人之间已经是比较均匀的,小组分的时候往往也比较均匀,且当 $K\ge4$ 个小组时真随机的交替率 $1-1/K$ 已落在人类偏好区间 0.57~0.80 内,再施压会把节奏推向 0.93 以上,反而机械化。
$$
p_s=(1-\varepsilon)\frac{w_s}{\sum_j w_j}+\frac{\varepsilon}{|\mathcal P|}
$$
来看这个公式:其中,$|\mathcal{P}|$ 就是我们前面提到的$N$。为了增添一点点刺激性,毕竟还是随机,你抽中一次就永远点不中是不好的,就要有被抽中的概率:然而保底发放的对象是在场者,不是欠账为正者。这一字之差决定了“被点过是否安全”:发给欠账为正者,$r_s=0$ 时 $p_s=0$ ,每人周期性「轮空」约 $\varepsilon$ 份额的安全窗口;发给在场者:任何时刻 $\forall s,\ p_s\ge\varepsilon/|\mathcal P|>0$ 。
视野的含义是“这个账本容许领先几次”。一次批量要消耗 $K$ 次此刻,所以性别视野跟随缩放:
$$
\text{horizon}_X=g\cdot K
$$
不乘会怎样?一个批次里前面的人消耗了该性别额度后,后面的名额只能去另一侧,强制成 2:1 之类的刻板构成,批内多样性被捏死。$g\cdot K$ 让每一批保有“3 人同性别偶尔发生的自由”,让上课睡觉有忧。(真随机 23%,乘开后实测 15~21%)。
个人视野不缩放,因为它已经在 $M$ 的递推里自动与 $K$ 解耦。
$\pi_s\propto\text{Multiplier}_s$ 在池内归一化:本身是“应该被点多少的明面声明”;$\text{Cap}_s$ 在池外由调用方维护:是「最多别超过」的背面约束。也就是说,想给好基友上强度?那得来点倍率,来个两倍三倍岂不是轻轻松松?
很高兴居然有人能愿意看到这里。鄙人不才,只能浅浅的讲点皮毛。总而言之:
写下”应得”的时候别只盯着历史,给未来 $H$ 次留个缓冲;然后用“应得减已得”当权重就够了;性别层再来一遍,但视野小到只允许领先半次;最后给每个人发一点 $\varepsilon$ 的保底,让没有人能确定自己安全。
自此,证毕,虽然这也不是证明。