天赐范式第185天:让漂变开始定量——扫N看选择主导边界

天赐范式第185天·第二篇:让漂变开始定量------扫N看选择主导边界


摘要

补184-2的N侧。有限种群漂变每代注入σ_g/√N噪声,选择每代推h²·S。扫N从20到1000(6个格点,50 seeds),Δ*均值≈0.005不随N变------选择响应是确定性的;Δ*std随N按1/√N缩放,从0.00478(N=20)缩到0.00070(N=1000)。信噪比从2.29升到18.09;理论边界N*≈3.1(SNR=1处),实际N=100时SNR=5.57,选择可靠主导。"选择何时主导"完整两面:遗传力侧(h²>0.5)+ 种群侧(N>N*)。


一、接续184-2:还差N侧

第184-2篇回答了"选择何时主导"的遗传力侧:h²>0.5时选择力超过环境噪声,主导方向(且是平滑过渡,不是相变)。

但"选择何时主导"还有第二侧------种群侧。有限种群有一个遗传力公式管不到的东西:漂变。每代繁殖抽样只有N个个体,等位基因频率会在抽样时随机漂移,注入σ_g/√N量级的噪声。种群越小,漂变噪声越大;种群足够大时,选择信号才能盖过它。

184-2答了一半,这篇把N侧补上:扫N,看漂变噪声和选择响应谁主导、边界在哪。


二、量纲与预测

两个力的量纲:

  • 漂变噪声 ≈ σ_g / √N(每代注入的抽样噪声)
  • 选择响应 ≈ h² · S(每代选择的确定性推动)

边界定义在信噪比=1处:

N* ≈ (σ_g / (h²·S))²

预测:N > N* 时选择主导(std小、Δ*确定);N < N* 时漂变主导(std大、Δ*被噪声淹没)。

本篇S≈0.022(N=200时),与185-1的S≈0.021在同一量级------两篇都用高斯加权选择,微小差异来自σ_g实测波动和有限种群噪声。


三、实验设计

模型与185-1完全一致(x = g + e,g' = TARGET + β(g_sel − TARGET) + v),选择机制高斯加权(与185-1一致),避免跨篇混机制。

固定:β=0.3, σ_e=0.02, σ_v=0.020, gen=500, seeds=50, x*=0.8, ω=0.1, TARGET=0.5。

扫描:N ∈ {20, 50, 100, 200, 500, 1000} 六个格点,每个格点50个seed取均值±std。


四、N扫描结果

N h² Δ* S σ_g 漂变噪声 选择响应 信噪比
20 0.4773 0.00592±0.00478 0.02105 0.0196 0.004379 0.010046 2.29
50 0.5066 0.00561±0.00358 0.02120 0.0205 0.002899 0.010738 3.70
100 0.5205 0.00494±0.00193 0.02242 0.0209 0.002095 0.011672 5.57
200 0.5128 0.00549±0.00151 0.02192 0.0206 0.001454 0.011242 7.73
500 0.5240 0.00516±0.00119 0.02331 0.0210 0.000939 0.012212 13.00
1000 0.5221 0.00522±0.00070 0.02291 0.0209 0.000661 0.011962 18.09

三个观察:

  1. Δ*均值≈0.005,不随N变化(0.00494--0.00592,无单调趋势)。选择响应是确定性力------群体大小不影响方向,只影响确定程度。这直接对上了185-1的闭式解:Δ*由景观参数和h²决定,N不改变Δ*的期望值。
  2. Δ*std随N缩小:0.00478(N=20)→ 0.00070(N=1000)。50个seed间的离散度就是漂变的指纹。
  3. 信噪比单调上升:SNR = 选择响应/漂变噪声 = (h²·S)/(σ_g/√N),从2.29(N=20)升到18.09(N=1000)。

五、Δ*离散度随N缩放

N Δ*均值 Δ*std std/均值 1/√N标度
20 0.00592 0.00478 0.807 0.2236
50 0.00561 0.00358 0.638 0.1414
100 0.00494 0.00193 0.390 0.1000
200 0.00549 0.00151 0.275 0.0707
500 0.00516 0.00119 0.230 0.0447
1000 0.00522 0.00070 0.134 0.0316

std按1/√N缩放成立。 看std/均值:0.807 → 0.134,与1/√N标度(0.2236 → 0.0316)同比例收缩------两者比值在3.6--5.1倍区间波动,没有随N系统发散。这意味着Δ*的seed间离散度确实是漂变主导的1/√N行为,不是别的噪声源。

N=100后std/均值已压到0.39以下,每个seed的Δ*都在均值约40%以内;N=1000时降到0.134,选择结果高度确定。


六、选择主导边界N*

用大N参考值估算:

  • σ_g = 0.0209
  • h² = 0.5221
  • S = 0.02291
  • h²·S = 0.011962
  • N* = (σ_g/(h²·S))² = 3.1

信噪比分布:

N SNR
20 2.29
50 3.70
100 5.57
200 7.73
500 13.00
1000 18.09

理论边界N*≈3.1(SNR=1处),实际扫到的最低N=20时SNR已是2.29。 这意味着在本实验的参数区(σ_g≈0.02、h²·S≈0.012)里,漂变几乎赢不了选择:哪怕20个成员的群落,选择信号也已经是漂变噪声的2.3倍。N=100时SNR=5.57,选择可靠主导。

N*≈3.1是理论边界,但种群大小N必须≥1,且实际种群不可能只有3个个体。 在本参数区(σ_g≈0.02、h²·S≈0.012),漂变主导区(N<N*)在生物学上不可达------这是本篇最大的诚实点。

N*低的原因是σ_g很小(0.0209)而h²·S相对大(0.012)------遗传方差供给少、选择力强,漂变的绝对量级σ_g/√N在任何可行N下都压不过选择响应。漂变要主导,得σ_g更大或h²·S更小,这是下一步扫σ_v×N双网格的活。


七、结论

问题 答案
Δ*均值随N变吗? 不变(≈0.005)。选择响应是确定性力,N只影响确定程度
Δ*std怎么随N缩? 按1/√N缩放(0.00478→0.00070),std/均值与1/√N同比例收缩
漂变何时淹没选择? 理论边界N*≈3.1(SNR=1处);本参数区N=20时SNR已=2.29,漂变几乎赢不了
选择何时可靠主导? h²>0.5(184-2遗传力侧)+ N>N*(185-2种群侧)

叙事弧:

  • 182-1:变异存续条件 σ_v > 0
  • 183-1:选择生效条件 h² > 0.5(半效界)
  • 184-2:h²=0.5是平滑过渡,公式全局适用
  • 185-1:S闭式解从景观先验算出,独立预测成立
  • 185-2:漂变定量化,"选择何时主导"完整两面 = 遗传力侧(h²>0.5) + 种群侧(N>N*)

降调:

  1. N*≈3.1是σ_v=0.02单点扫描的结论。 σ_v增大→σ_g增大→N*上移(漂变噪声基数变大)。要看清漂变主导区,需要扫σ_v×N双网格------这是下一步的债。

  2. std/均值与1/√N标度同比例收缩(比值在3.6--5.1间波动),但未严格等于1/√N。 偏差来自每格点σ_g实测微差(0.0196--0.0210间波动)和选择对漂变的非线性压缩,不是错误。

  3. N=20时h²=0.4773略低于0.5------小种群下遗传方差估计本身受漂变干扰,h²侧边界和N侧边界在20人量级会互相污染,解读N=20行时要谨慎。

  4. 单位点模型。 多位点、上位效应、连锁不平衡待后续。

  5. SNR基于稳态Δ*计算。 模拟跑500代到稳态后取值,有限世代下Δ*仍在波动,SNR是稳态量不是瞬态量。

系列还在逐步建设中,完善是和伙伴们的努力方向。


附录:完整代码

python 复制代码
# -*- coding: utf-8 -*-
"""
天赐范式第185天:让漂变开始定量------扫N看选择主导边界 V3.3.23.0
接续184-2(h²侧回答"选择何时主导"),补N侧。

有限种群漂变每代注入σ_g/√N噪声,选择每代推h²·S------两者相当时选择信号被淹没。
扫N(20/50/100/200/500/1000),看多seed间Δ*离散度随N怎么缩、选择主导边界N*在哪。

预测:N大→std小→选择主导;N小→std大→漂变主导
边界N*:h²·S ≈ σ_g/√N* → N* ≈ (σ_g/(h²·S))²

选择机制:高斯加权(与185-1一致)
"""

import sys
import math
import numpy as np

if hasattr(sys.stdout, 'reconfigure'):
    sys.stdout.reconfigure(encoding='utf-8')

PID = "TC-185-V3.3.23.0"

TARGET = 0.5
FITNESS_PEAK = 0.8
FITNESS_WIDTH = 0.10
BETA = 0.3
SIGMA_E = 0.02
N_GENERATIONS = 500
N_SEEDS = 50

SIGMA_V = 0.020

N_GRID = [20, 50, 100, 200, 500, 1000]


def bar(title):
    print("=" * 72)
    print("  " + title)
    print("=" * 72)
    print()


def sub(title):
    print("【" + title)
    print("-" * 72)


def fitness(x):
    return np.exp(-(x - FITNESS_PEAK) ** 2 / (2 * FITNESS_WIDTH ** 2))


def run_one(n_pop, seed):
    rng = np.random.RandomState(seed)
    genes = rng.normal(TARGET, 0.01, n_pop)

    for gen in range(N_GENERATIONS):
        phenos = genes + rng.normal(0, SIGMA_E, n_pop)
        fits = fitness(phenos)
        probs = fits / fits.sum()
        sel_idx = rng.choice(n_pop, size=n_pop, p=probs)
        parent_genes = genes[sel_idx]
        genes = TARGET + BETA * (parent_genes - TARGET) + rng.normal(0, SIGMA_V, n_pop)

    var_g = float(np.var(genes))
    mean_g = float(np.mean(genes))
    h2 = var_g / (var_g + SIGMA_E ** 2)

    phenos = genes + rng.normal(0, SIGMA_E, n_pop)
    fits = fitness(phenos)
    mean_parents_x = float(np.mean(phenos))
    weighted_x = float(np.average(phenos, weights=fits))
    S = weighted_x - mean_parents_x

    delta_star = mean_g - TARGET

    return h2, delta_star, S, var_g, mean_g


def main():
    bar(f"{PID}  让漂变开始定量------扫N看选择主导边界")
    print(f"模型: x=g+e, g'=TARGET+β(g_sel-TARGET)+v")
    print(f"选择机制: 高斯加权(与185-1一致)")
    print(f"固定: β={BETA}, σ_e={SIGMA_E}, σ_v={SIGMA_V}, gen={N_GENERATIONS}, seeds={N_SEEDS}")
    print(f"fitness峰: x*={FITNESS_PEAK}, ω={FITNESS_WIDTH}, TARGET={TARGET}")
    print(f"扫描: N = {N_GRID}")
    print(f"预测: 漂变噪声≈σ_g/√N, 选择响应≈h²·S, 边界N*≈(σ_g/(h²·S))²")
    print()

    sub("N扫描结果(多seed均值±std)")
    print(f"{'N':>6s}  {'h²':>8s}  {'Δ*':>12s}  {'S':>10s}  {'σ_g':>8s}  {'漂变噪声':>10s}  {'选择响应':>10s}  {'信噪比':>6s}")
    print("-" * 80)

    results = []
    for n_pop in N_GRID:
        h2_list = []
        delta_list = []
        S_list = []
        var_g_list = []
        for seed in range(N_SEEDS):
            h2, delta, S, var_g, mean_g = run_one(n_pop, seed)
            h2_list.append(h2)
            delta_list.append(delta)
            S_list.append(S)
            var_g_list.append(var_g)

        h2_mean = np.mean(h2_list)
        delta_mean = np.mean(delta_list)
        delta_std = np.std(delta_list)
        S_mean = np.mean(S_list)
        var_g_mean = np.mean(var_g_list)
        sigma_g = math.sqrt(var_g_mean)

        drift_noise = sigma_g / math.sqrt(n_pop)
        selection_response = h2_mean * S_mean
        snr = selection_response / drift_noise if abs(drift_noise) > 1e-10 else float('nan')

        results.append({
            'n_pop': n_pop,
            'h2_mean': h2_mean,
            'delta_mean': delta_mean, 'delta_std': delta_std,
            'S_mean': S_mean,
            'sigma_g': sigma_g,
            'drift_noise': drift_noise,
            'selection_response': selection_response,
            'snr': snr,
        })

        print(f"{n_pop:>6d}  {h2_mean:>8.4f}  {delta_mean:>8.5f}±{delta_std:.5f}  {S_mean:>8.5f}  {sigma_g:>8.4f}  {drift_noise:>10.6f}  {selection_response:>10.6f}  {snr:>6.2f}")

    print()

    sub("漂变 vs 选择:Δ*离散度随N缩放")
    print(f"{'N':>6s}  {'Δ*均值':>10s}  {'Δ*std':>10s}  {'std/均值':>8s}  {'1/√N标度':>10s}")
    print("-" * 52)
    for r in results:
        cv = r['delta_std'] / abs(r['delta_mean']) if abs(r['delta_mean']) > 1e-10 else float('nan')
        inv_sqrt_n = 1.0 / math.sqrt(r['n_pop'])
        print(f"{r['n_pop']:>6d}  {r['delta_mean']:>10.5f}  {r['delta_std']:>10.5f}  {cv:>8.3f}  {inv_sqrt_n:>10.4f}")

    print()

    sub("选择主导边界N*")
    r_ref = results[-1]
    sigma_g_ref = r_ref['sigma_g']
    h2_ref = r_ref['h2_mean']
    S_ref = r_ref['S_mean']
    N_star = (sigma_g_ref / (h2_ref * S_ref)) ** 2

    print(f"用大N参考值估算边界:")
    print(f"  σ_g = {sigma_g_ref:.4f}")
    print(f"  h² = {h2_ref:.4f}")
    print(f"  S = {S_ref:.5f}")
    print(f"  h²·S = {h2_ref * S_ref:.6f}")
    print(f"  N* = (σ_g/(h²·S))² = {N_star:.1f}")
    print()

    print(f"信噪比随N变化:")
    for r in results:
        bar_str = "█" * int(r['snr']) if r['snr'] < 50 else "█" * 50
        print(f"  N={r['n_pop']:>5d}: SNR={r['snr']:>6.2f} {bar_str}")

    print()

    sub("结论")
    print(f"184-2:h²侧回答'选择何时主导'(h²>0.5,平滑过渡)")
    print(f"185-2:N侧回答'选择何时主导'")
    print(f"       漂变噪声≈σ_g/√N,选择响应≈h²·S")
    print(f"       边界N*≈{N_star:.0f}(信噪比=1处)")
    print(f"       N>N*时选择主导,N<N*时漂变主导")
    print()
    print(f"  '选择何时主导'完整两面:遗传力侧(h²>0.5) + 种群侧(N>N*)")


if __name__ == "__main__":
    main()

天赐范式 V3.3.23.0 · 2026-10-04

相关推荐
Jo乔戈里1 小时前
免费本地搜图软件
图像处理·python·搜索引擎·ai
for_ever_love__1 小时前
字符串处理——f-string、切片与正则,清洗文本的第一把刀
python·大模型·虚拟环境
夜晚回家1 小时前
Python 零基础入门 | 输入的数字为什么不能直接算
开发语言·python
打工仔折腾 AI1 小时前
把AI Agent托管在家用电脑:UU远程终端与端口映射实测记录
人工智能·后端·python·langchain·ai agent 实战
yivifu2 小时前
中文古籍电子书注释集成
前端·javascript·python·beautifulsoup·epub
零基础1232 小时前
Agent 的 Memory 怎么做科研:以中医诊断场景为例
人工智能·经验分享·python·语言模型
databook2 小时前
面向数据工程师的正则表达式:从日志清洗到字段提取
python·正则表达式·数据分析
ss2733 小时前
AI全栈实战 | 3.2-01 Python 基础:四大数据容器怎么选,推导式为什么是 Pythonic 的灵魂
开发语言·人工智能·python
计算机毕业编程指导师3 小时前
【大数据毕设选题推荐】基于Spark的WTA职业网球赛事演变与竞技格局分析系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习 深度学习
大数据·python·计算机·spark·毕业设计·课程设计·wta网球