Skill: nic-yuan/08-data-growth (version 1.0.0)

--- name: community-group-buying-data-growth description: 社区团购数据与增长全链路技能包。涵盖指标体系搭建、AARRR漏斗分析、增长策略、数据驱动决策方法论及配套工具。适用于平台运营负责人、数据分析师。 version: 1.0.0 created_at: 2026-04-14 license: MIT github_url: null --- # 模块八：数据与增长 > **模块边界说明** > 本模块聚焦"怎么看数据、怎么用数据驱动增长"，即指标体系、漏斗分析、增长实验。 > 选品决策 → 模块一（选品策略） > 获客渠道 → 模块三（获客与留存） > 营销促销 → 模块六（营销与促销） > 团长运营 → 模块二（团长运营） > 各模块边界独立，不重叠。 --- ## 知识库 ### 8.1 社区团购核心指标体系 ``` 社区团购指标金字塔： GMV（最终结果） △ ┌───────┴───────┐ 订单量 客单价 △ △ 单量=UV×转化率 客单=SKU数×品类单价 底层驱动指标： → 用户数（UV/DAU/MAU） → 转化率（下单率） → 复购率（购买频次） → 团点数（覆盖密度） → SKU数（商品丰富度） --- 五大核心指标详解： 指标1：GMV（成交总额） 公式：GMV = 订单量 × 客单价 行业参考：多多买菜日均 GMV 约 5 亿（2023年） 健康范围：月环比增长 5-15% 指标2：订单量 公式：订单量 = 活跃用户数 × 人均下单频次 行业参考：头部平台日均 1000-5000 万单 指标3：客单价 公式：客单价 = GMV / 订单量 行业参考：35-55 元（多多买菜约 30 元，美团约 45 元） 指标4：复购率 公式：复购率 = 当期购买≥2次的用户 / 当期总购买用户 健康标准： 次日复购率：> 30% 优秀 / 20-30% 一般 / < 20% 危险 7日复购率：> 50% 优秀 / 35-50% 一般 / < 35% 危险 30日复购率：> 70% 优秀 / 55-70% 一般 / < 55% 危险 指标5：获客成本（CAC） 公式：CAC = 营销总费用 / 新用户数 行业参考： 兴盛优选：约 8-12 元/人（最低） 美团优选：约 12-18 元/人 多多买菜：约 15-25 元/人（含补贴） 行业健康线：< 20 元/人 ``` --- ### 8.2 AARRR增长漏斗 ``` AARRR漏斗（社区团购版本）： Acquisition（获客） → 渠道曝光 → 落地页访问 → 关注/注册 → 核心指标：获客成本（CAC）、渠道ROI Activation（激活） → 新用户完成首单 → 核心指标：首单转化率（目标 > 40%） Retention（留存） → 用户持续在平台下单 → 核心指标：次日/7日/30日复购率 Revenue（变现） → 用户贡献的GMV → 核心指标：LTV（用户生命周期价值）、ROI Referral（推荐） → 用户推荐新用户 → 核心指标：K因子（推荐转化率）、分享率 --- 各层级漏斗指标： 层级 指标 健康值 危险值 ───────────────────────────────────────────────────── 获客 首单转化率 > 40% < 25% 获客 CAC < 15元 > 30元 激活 新用户7日复购率 > 45% < 25% 留存 次日留存率 > 35% < 20% 留存 30日复购率 > 60% < 40% 变现 LTV/CAC > 3.0 < 1.5 变现 月均购买频次 > 4次 < 2次 推荐 K因子 > 0.3 < 0.1 ``` --- ### 8.3 增长归因分析 ``` 增长归因三种方法： 方法1：末次归因（Last Click） → 归功于用户最后一次触达的渠道 → 适合：短决策周期（社区团购用户决策快） → 缺点：忽视前期触达的价值 方法2：线性归因（Linear） → 将功劳平均分配给用户接触的所有渠道 → 适合：多触点协同的品牌活动 → 缺点：淡化关键渠道的作用 方法3：时间衰减归因（Time Decay） → 越接近转化的渠道，权重越高 → 适合：社区团购（用户多次触达后下单） → 权重参考：7天内首次触达权重 20%，最后一次 50% 社区团购推荐归因组合： → 首单归因：主要归功于团长的私域推荐（权重 60%） → 次日留存归因：主要归功于首单体验（权重 40%）+ 群运营（30%） → 复购归因：主要归功于商品品质（50%）+ 团长关系（30%） ``` --- ### 8.4 各平台数据体系对比 ``` 美团优选：数据驱动型 数据体系： → 实时数据大盘：GMV/单量/客诉实时监控 → 用户标签体系：RFM分层 + 行为标签（100+标签） → 供应链数据：供应商实时库存/配送轨迹 → BI系统：美团内部数据分析工具（BI系统） 核心增长策略： → 用户分层运营：高价值用户专享活动 → 数据选品：基于历史数据预测爆品 → 精准营销：基于用户标签的个性化推荐 多多买菜：AI算法驱动型 数据体系： → 拼多多分布式数据中台（日均处理数据量 PB 级） → 用户画像：社交关系链 + 购买行为（拼多多全平台数据） → 商品推荐：AI算法个性化推荐（"千人千面"） → 果园/游戏联动：用游戏数据辅助用户增长 核心增长策略： → 社交裂变：用拼多多社交玩法（拼团/助力/砍价） → 算法选品：AI预测爆品，减少人工选品失误 → 动态定价：基于供需关系的实时价格调整 兴盛优选：本地化数据驱动型 数据体系： → 区域订单预测：基于历史数据预测区域单量 → 团长绩效系统：实时追踪团长订单/复购 → 供应商数据：区域供应商供货数据追踪 核心增长策略： → 区域深耕：一个区域做透再扩张 → 团长密度优先：先提升区域密度，再做新区域 → 用户口碑驱动：依靠服务质量带动自然增长 淘菜菜：阿里生态数据型 数据体系： → 88VIP用户数据：淘宝/支付宝全生态数据 → 地理围栏数据：精准社区粒度用户画像 → 供应链数据：阿里零售通供应链数据支持 核心增长策略： → 生态联动：淘宝/支付宝/饿了么多入口导流 → 会员体系：用88VIP会员权益锁定高价值用户 ``` --- ### 8.5 RFM用户分层模型 ``` RFM模型（社区团购适用）： 三维度定义： R（Recency 最近购买距今天数）： R1：< 7天（极度活跃） R2：7-14天（活跃） R3：14-30天（沉默） R4：30-60天（流失风险） R5：> 60天（已流失） F（Frequency 月均购买频次）： F1：< 1次（低频） F2：1-3次（一般） F3：3-5次（较高） F4：5-8次（高频） F5：> 8次（极度忠诚） M（Monetary 月均消费金额）： M1：< 30元（低价值） M2：30-60元（一般） M3：60-100元（较高） M4：100-200元（高价值） M5：> 200元（超高价值） --- 社区团购用户分层矩阵（8类）： 高价值层（贡献 50-60% GMV）： ① 顶尖用户（R≤3 & F≥4 & M≥4）：月均消费 ≥¥200，忠诚度最高 → 策略：专属服务，不轻易打折，维护关系 ② 高价值用户（R≤3 & F≥3 & M≥3）：月均 ¥100-200 → 策略：VIP权益，会员体系，专属优惠券 成长层（贡献 20-25% GMV）： ③ 潜力用户（R≤3 & F≥3 & M≤2）：频次高但客单低 → 策略：组合套餐，满减活动，引导加购 ④ 提升用户（R≤3 & F≤2 & M≥3）：客单高但频次低 → 策略：复购提醒，限时优惠，积分体系 流失风险层（贡献 15-20% GMV）： ⑤ 沉默用户（R4 & F≥2）：近期未购买，但有一定购买历史 → 策略：定向召回券（高额），激活活动 ⑥ 流失风险（R4 & F=1）：最后一次购买距今30-60天，且仅购1次 → 策略：专属流失券，客服电话回访 低价值层（贡献 5-10% GMV）： ⑦ 羊毛用户（R≤3 & F≤1 & M≤1）：低价敏感，补贴依赖 → 策略：控制补贴，只参与大促，不做日常补贴 ⑧ 流失用户（R5）：>60天未购买 → 策略：周期性推送，低成本唤醒，沉默放弃 --- RFM计算公式： R得分 = max(0, 5 - ceil(今天 - 最后购买日期) / 7) （距今天数越少，得分越高） F得分 = min(5, ceil(月均购买次数)) （月均购买次数越多，得分越高） M得分 = min(5, ceil(月均消费金额 / 30)) （月均消费每增加30元，升1分，上限5分） 综合得分 = R得分×40% + F得分×30% + M得分×30% 示例： 用户A：最后购买距今3天（R=5），月均4次（F=4），月均¥90（M=3） → 综合得分 = 5×0.4 + 4×0.3 + 3×0.3 = 2.0 + 1.2 + 0.9 = 4.1 → 高价值用户 ``` --- ### 8.6 增长四象限分析 ``` 业务增长四象限（社区团购适用）： 客单价 △ 高 │ 高 ┌───────────┼───────────┐ │ │ │ 低│ 拉新驱动 │ 利润优化 │ 高 │ │ │ ├───────────┤ │ │ │ 低│ 流失风险 │ 均衡健康 │ 低 │ │ │ └───────────┴───────────┘ △ 客单价 象限1：高客单价 + 低复购 = 拉新驱动型 特征：主要靠拉新增长，老用户留存差 策略：加强留存运营，提升复购频次 代表：成熟期平台的新市场开拓阶段 象限2：高客单价 + 高复购 = 均衡健康型（最优） 特征：增长质量高，LTV/CAC 表现优秀 策略：维持现状，适度扩大规模 代表：兴盛优选湖南市场 象限3：低客单价 + 低复购 = 流失风险型（危险） 特征：既没有高价值用户，又留不住人 策略：全面诊断，从获客到留存全面整改 代表：十荟团崩溃前 象限4：低客单价 + 高复购 = 利润优化型 特征：用户忠诚度高，但消费力有限 策略：提升客单价的专项运营（如组合套餐） 代表：多多买菜部分低客单价用户群 ``` --- ## 方法论 ### 8.7 AB测试统计基础 ``` AB测试统计显著性核心公式： 一、最小样本量公式（双侧检验） n = (Z_α/2 + Z_β)² × [p₁(1-p₁) + p₂(1-p₂)] / (p₂ - p₁)² 其中： n = 每组最小样本量 p₁ = 对照组基准转化率 p₂ = 实验组预期转化率 Δ = p₂ - p₁（最小可检测差异） Z_α/2 = 置信度参数（α=0.05时，Z_α/2=1.96） Z_β = 统计功效参数（通常取0.84，对应80%功效） 示例： 对照组转化率 p₁ = 0.30 期望提升至 p₂ = 0.33（绝对提升 +3pp） 则 Δ = 0.03 n = (1.96 + 0.84)² × [0.30×0.70 + 0.33×0.67] / 0.03² = 7.84 × [0.21 + 0.221] / 0.0009 = 7.84 × 0.431 / 0.0009 ≈ 3,380 组 每组需要约 3,380 样本，两组共 6,760 样本 --- 二、常用最小样本量速查表（社区团购场景） ┌────────────────────────────────────────────────────────┐ │ 转化率提升幅度 每组最小样本量 总样本量（两组） │ │ ───────────────────────────────────── │ │ 绝对提升 +1pp 约 9,200 约 18,400 │ │ 绝对提升 +2pp 约 2,300 约 4,600 │ │ 绝对提升 +3pp 约 1,000 约 2,000 │ │ 绝对提升 +5pp 约 370 约 740 │ │ 相对提升 +10% 约 2,900 约 5,800 │ │ 相对提升 +20% 约 680 约 1,360 │ └────────────────────────────────────────────────────────┘ 假设：基准转化率30%，α=0.05，统计功效=80% --- 三、Z值计算公式（两比例Z检验） Z = (p₂ - p₁) / √[p̄(1-p̄) × (1/n₁ + 1/n₂)] 其中： p₁, p₂ = 两组转化率 n₁, n₂ = 两组样本量 p̄ = 合并比例 = (x₁ + x₂) / (n₁ + n₂) x₁, x₂ = 两组转化人数 判断标准： |Z| > 1.96 → p < 0.05，统计显著 |Z| > 1.65 → p < 0.10，边缘显著 |Z| < 1.65 → p ≥ 0.10，不显著 --- 四、单侧 vs 双侧检验选择 双侧检验（默认使用）： → 适用于：不知道方向，只想知道"有没有差异" → Z临界值：1.96（对应95%置信度） 单侧检验（慎用）： → 适用于：有强理论/业务依据确信实验组 > 对照组 → Z临界值：1.65（对应95%置信度，单侧） → 注意：单侧检验更容易显著，但可能错过反向效果 社区团购实践建议：默认用双侧检验，避免单侧检验的滥用 --- 五、统计功效（Power）说明 统计功效 = 当实验组真实效果更优时，正确判断出差异的概率 行业标准：功效 ≥ 80%（β ≤ 20%） → 含义：如果实验组真实提升3pp，有80%概率被检测出来 → 低于80%：容易错过真实效果（II类错误） → 高于90%：样本量需求激增，成本过高 功效-样本量关系： 功效80%：n = (1.96+0.84)² × ... ≈ 基准n 功效90%：n = (1.96+1.28)² × ... ≈ 基准n × 1.7 功效95%：n = (1.96+1.645)² × ... ≈ 基准n × 2.7 --- 六、多重比较问题（Multiple Testing） 同时进行多组AB测试时，犯I类错误（假阳性）的概率会膨胀： Bonferroni校正公式： 校正后 α* = α / k 其中 k = 同时进行的测试数量 示例： 同时进行5个独立测试，原始α=0.05 校正后：α* = 0.05 / 5 = 0.01 判断标准：Z > 2.58 才算显著（而非1.96） 实践建议： → 同时超过3个测试时建议使用Bonferroni校正 → 或使用FDR（False Discovery Rate）控制方法 → 优先级较低的小测试可先跑一周，无信号再加大样本 ``` --- ### 8.8 数据驱动决策 SOP ``` 数据驱动决策五步法： Step 1：明确问题（定义业务问题） 不好的问题：GMV 下降了，怎么办？ 好的问题：湖南区域 12 月 GMV 环比下降 12%，原因是新用户下单减少还是老用户复购下降？ 工具：使用"5Why分析法"追问根因 Step 2：数据提取（找到相关数据） 数据来源：

path: references/continuation.md
content: #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
AB测试结果分析器
输入：实验组/对照组数据
输出：统计显著性 + 效果评估 + 决策建议
"""

import math
from dataclasses import dataclass
from typing import Dict


@dataclass
class ABTestResult:
    """AB测试结果"""
    experiment_name: str
    # 样本量
    control_size: int
    experiment_size: int
    # 转化用户数
    control_converted: int
    experiment_converted: int
    # 总价值（可选）
    control_value: float = 0.0
    experiment_value: float = 0.0


def calculate_significance(control_rate: float, experiment_rate: float,
                          control_size: int, experiment_size: int) -> Dict:
    """计算统计显著性（Z-test）"""
    if control_size == 0 or experiment_size == 0:
        return {"error": "样本量为0"}

    # 合并比例（使用传入的转化率 × 样本量估算总数）
    total_converted_est = (control_rate * control_size + experiment_rate * experiment_size)
    pooled_rate = total_converted_est / (control_size + experiment_size)

    # 标准误差
    se = math.sqrt(pooled_rate * (1 - pooled_rate) * (1/control_size + 1/experiment_size))

    if se == 0:
        return {"error": "标准误差为0"}

    # Z值
    z = (experiment_rate - control_rate) / se

    # P值（单侧检验）
    # 使用近似：|z| > 1.96 → p < 0.05
    if abs(z) >= 1.96:
        significance = "✅ 显著（p < 0.05）"
    elif abs(z) >= 1.65:
        significance = "🟡 边缘显著（p < 0.10）"
    else:
        significance = "❌ 不显著"

    # 置信区间
    margin = 1.96 * se
    ci_lower = (experiment_rate - control_rate) - margin
    ci_upper = (experiment_rate - control_rate) + margin

    return {
        "z_value": round(z, 3),
        "significance": significance,
        "confidence_interval": f"[{ci_lower*100:.2f}%, {ci_upper*100:.2f}%]",
        "pooled_rate": pooled_rate,
    }


def analyze_ab_test(result: ABTestResult) -> Dict:
    """分析AB测试结果"""

    # 计算转化率
    control_rate = result.control_converted / result.control_size if result.control_size > 0 else 0
    experiment_rate = result.experiment_converted / result.experiment_size if result.experiment_size > 0 else 0

    # 计算提升
    absolute_lift = experiment_rate - control_rate
    relative_lift = absolute_lift / control_rate * 100 if control_rate > 0 else 0

    # 统计显著性
    sig_result = calculate_significance(
        control_rate, experiment_rate,  # 传入转化率（非转化人数）
        result.control_size, result.experiment_size
    )

    # 人均价值（如果有）
    control_avg_value = result.control_value / result.control_converted if result.control_converted > 0 else 0
    experiment_avg_value = result.experiment_value / result.experiment_converted if result.experiment_converted > 0 else 0

    # 决策建议
    decision = ""
    if "✅ 显著" in sig_result.get("significance", ""):
        if absolute_lift > 0:
            decision = "🟢 效果正向显著 → 建议全量推广"
        else:
            decision = "🔴 效果负向显著 → 建议停止，保留原方案"
    elif "🟡 边缘" in sig_result.get("significance", ""):
        decision = "🟡 边缘显著 → 可选择性推广，监控更长周期"
    else:
        decision = "⚪ 效果不显著 → 建议放弃或重测"

    return {
        "实验名称": result.experiment_name,
        "样本量": f"对照组 {result.control_size:,} / 实验组 {result.experiment_size:,}",
        "转化率": {
            "对照组": f"{control_rate*100:.2f}%（{result.control_converted:,}/{result.control_size:,}）",
            "实验组": f"{experiment_rate*100:.2f}%（{result.experiment_converted:,}/{result.experiment_size:,}）",
        },
        "效果提升": {
            "绝对提升": f"{absolute_lift*100:+.2f}pp",
            "相对提升": f"{relative_lift:+.1f}%",
        },
        "统计检验": {
            "Z值": sig_result.get("z_value", "N/A"),
            "显著性": sig_result.get("significance", "N/A"),
            "95%置信区间": sig_result.get("confidence_interval", "N/A"),
        },
        "决策": decision,
    }


def run():
    print("=" * 55)
    print("AB测试结果分析器")
    print("=" * 55)

    test = ABTestResult(
        experiment_name="简化下单流程测试",
        control_size=5000,
        experiment_size=5000,
        control_converted=1450,
        experiment_converted=1680,
    )

    result = analyze_ab_test(test)

    print(f"\n实验：{result['实验名称']}")
    print(f"样本量：{result['样本量']}")
    print(f"\n转化率：")
    print(f"  对照组：{result['转化率']['对照组']}")
    print(f"  实验组：{result['转化率']['实验组']}")
    print(f"\n效果提升：")
    print(f"  绝对提升：{result['效果提升']['绝对提升']}")
    print(f"  相对提升：{result['效果提升']['相对提升']}")
    print(f"\n统计检验：")
    print(f"  Z值：{result['统计检验']['Z值']}")
    print(f"  显著性：{result['统计检验']['显著性']}")
    print(f"  置信区间：{result['统计检验']['95%置信区间']}")
    print(f"\n决策：{result['决策']}")


if __name__ == "__main__":
    run()
```

### Tool 4: 归因分析器

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
归因分析器
输入：各渠道转化数据 + 归因方法
输出：各渠道归因权重/GMV分配/推荐方法
"""


def calculate_attribution(
    channels: list,
    conversions_by_channel: list,
    revenue_by_channel: list,
    method: str = "time_decay",
) -> dict:
    """
    计算渠道归因权重

    Args:
        channels: 渠道名称列表（按用户触达顺序排列）
        conversions_by_channel: 各渠道转化人数
        revenue_by_channel: 各渠道带来的GMV（元）
        method: 归因方法
            - "last": 末次归因（最后一次触达渠道全功）
            - "linear": 线性归因（平均分配）
            - "time_decay": 时间衰减归因（越近越高）
    """
    n = len(channels)
    total_conversions = sum(conversions_by_channel) or 1
    total_revenue = sum(revenue_by_channel) or 1

    if method == "last":
        # 末次归因：最后一个渠道获得100%权重
        weights = [0.0] * n
        weights[-1] = 1.0
        desc = "末次归因：最后一次触达渠道获得100%功劳"

    elif method == "linear":
        # 线性归因：平均分配
        weights = [1.0 / n] * n
        desc = "线性归因：各渠道平均分配功劳"

    elif method == "time_decay":
        # 时间衰减：越接近转化的渠道权重越高
        # 位置 i 的权重 = (i+1) / sum(1..n)
        position_weights = [(i + 1) for i in range(n)]
        total_pos = sum(position_weights)
        weights = [w / total_pos for w in position_weights]
        desc = "时间衰减：越接近转化，权重越高"

    else:
        weights = [1.0 / n] * n
        desc = "默认线性归因"

    # 各渠道分配结果
    channel_results = {}
    for i, ch in enumerate(channels):
        conv_attr = int(conversions_by_channel[i] * weights[i])
        rev_attr = revenue_by_channel[i] * weights[i]
        channel_results[ch] = {
            "归因转化": conv_attr,
            "归因GMV": f"¥{rev_attr:,.0f}",
            "归因权重": f"{weights[i]*100:.1f}%",
            "原始转化": conversions_by_channel[i],
            "原始GMV": f"¥{revenue_by_channel[i]:,.0f}",
        }

    # 推荐方法
    if n <= 2:
        recommended = "last"
        recommended_desc = "触达渠道少，用末次归因更合理"
    else:
        recommended = "time_decay"
        recommended_desc = "多触点场景，用时间衰减归因更准确"

    return {
        "归因方法": method,
        "方法说明": desc,
        "各渠道归因": channel_results,
        "推荐方法": recommended,
        "推荐理由": recommended_desc,
        "总转化（归因后）": int(total_conversions),
        "总GMV（归因后）": f"¥{total_revenue:,.0f}",
    }


def run():
    print("=" * 55)
    print("归因分析器")
    print("=" * 55)

    channels = ["团长推荐", "朋友圈分享", "地推活动", "自然流量"]
    conversions = [1200, 800, 600, 400]
    revenues = [42000, 28000, 21000, 14000]

    print(f"\n渠道数据：")
    for i, ch in enumerate(channels):
        print(f"  {ch}：{conversions[i]}转化，¥{revenues[i]:,}GMV")

    print(f"\n--- 末次归因 ---")
    result = calculate_attribution(channels, conversions, revenues, "last")
    for ch, data in result["各渠道归因"].items():
        print(f"  {ch}：权重{data['归因权重']}，归因GMV {data['归因GMV']}")

    print(f"\n--- 线性归因 ---")
    result = calculate_attribution(channels, conversions, revenues, "linear")
    for ch, data in result["各渠道归因"].items():
        print(f"  {ch}：权重{data['归因权重']}，归因GMV {data['归因GMV']}")

    print(f"\n--- 时间衰减归因（推荐）---")
    result = calculate_attribution(channels, conversions, revenues, "time_decay")
    for ch, data in result["各渠道归因"].items():
        print(f"  {ch}：权重{data['归因权重']}，归因GMV {data['归因GMV']}")

    print(f"\n推荐方法：{result['推荐方法']} - {result['推荐理由']}")


if __name__ == "__main__":
    run()
```

### Tool 5: 最小样本量计算器

> **接口说明**
> 输入参数（SampleSizeParams dataclass）：
> - `control_rate`: 对照组基准转化率（浮点数，如 0.30 表示 30%）
> - `minimum_detectable_effect`: 最小可检测绝对提升（浮点数，如 0.03 表示 +3pp）
> - `alpha`: 显著性水平（默认 0.05）
> - `power`: 统计功效（默认 0.80）
>
> 输出：每组最小样本量、总样本量、预计测试周期
>
> 调用示例：
> ```python
> params = SampleSizeParams(control_rate=0.30, minimum_detectable_effect=0.03)
> result = calculate_sample_size(params)
> print(result["每组样本量"])  # → 约 3380
> ```

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
最小样本量计算器
基于Z检验的双侧比例比较样本量公式
n = (Z_α/2 + Z_β)² × [p₁(1-p₁) + p₂(1-p₂)] / (p₂-p₁)²
"""

import math
from dataclasses import dataclass
from typing import Dict


# Z值表（标准正态分布分位数，完整查表）
Z_VALUES = {
    # alpha（双侧检验，显著性水平）
    0.20: 1.2816,
    0.10: 1.6449,
    0.05: 1.9600,
    0.02: 2.3263,
    0.01: 2.5758,
    0.005: 2.8070,
    0.001: 3.2905,
    # power（统计功效）
    0.50: 0.0000,
    0.60: 0.2533,
    0.70: 0.5244,
    0.75: 0.6745,
    0.80: 0.8416,
    0.85: 1.0364,
    0.90: 1.2816,
    0.95: 1.6449,
}


@dataclass
class SampleSizeParams:
    """样本量计算参数"""
    control_rate: float          # 对照组基准转化率
    minimum_detectable_effect: float  # 最小可检测绝对提升（pp）
    alpha: float = 0.05          # 显著性水平（双侧）
    power: float = 0.80          # 统计功效


def get_z_value(p: float) -> float:
    """根据概率 p 获取对应 Z 值（标准正态分布分位数）
    使用精确查表，对于表中相邻值使用线性插值
    """
    if p <= 0:
        return float('-inf')
    if p >= 1:
        return float('+inf')

    sorted_items = sorted(Z_VALUES.items())
    keys = [k for k, v in sorted_items]

    # 精确匹配
    for key, z in sorted_items:
        if abs(p - key) < 0.0001:
            return z

    # 边界外推
    if p < keys[0]:
        return Z_VALUES[keys[0]]
    if p > keys[-1]:
        return Z_VALUES[keys[-1]]

    # 线性插值（相邻两个键之间）
    for i in range(len(keys) - 1):
        k_low, k_high = keys[i], keys[i + 1]
        if k_low < p < k_high:
            z_low = Z_VALUES[k_low]
            z_high = Z_VALUES[k_high]
            frac = (p - k_low) / (k_high - k_low)
            return z_low + frac * (z_high - z_low)

    # fallback
    return 1.96


def calculate_sample_size(params: SampleSizeParams) -> Dict:
    """计算AB测试所需最小样本量"""

    p1 = params.control_rate
    p2 = p1 + params.minimum_detectable_effect
    alpha = params.alpha
    power = params.power

    # 获取Z值
    z_alpha_2 = get_z_value(1 - alpha / 2)  # 双侧检验
    z_beta = get_z_value(power)

    # 样本量公式
    pooled_var = p1 * (1 - p1) + p2 * (1 - p2)
    effect_size = p2 - p1

    n = (z_alpha_2 + z_beta) ** 2 * pooled_var / (effect_size ** 2)

    # 向上取整
    n_per_group = math.ceil(n)

    # 预计测试周期（日均新用户数）
    daily_users_estimate = 500  # 默认假设，可调整
    days_per_group = math.ceil(n_per_group / daily_users_estimate)

    # 速查表参考（用于对比）
    quick_ref = _generate_quick_ref(p1)

    return {
        "参数": {
            "对照组转化率": f"{p1*100:.1f}%",
            "实验组预期转化率": f"{p2*100:.1f}%",
            "最小可检测提升": f"+{params.minimum_detectable_effect*100:.1f}pp",
            "显著性水平": f"α={alpha}（双侧）",
            "统计功效": f"{power*100:.0f}%",
        },
        "计算结果": {
            "每组最小样本量": f"{n_per_group:,}",
            "总样本量（两组）": f"{n_per_group * 2:,}",
            "预计测试周期": f"约{days_per_group}天（假设日均新用户{daily_users_estimate}）",
        },
        "速查表参考": quick_ref,
    }


def _generate_quick_ref(base_rate: float) -> Dict:
    """生成速查表"""
    effects = [0.01, 0.02, 0.03, 0.05]
    ref = {}
    for effect in effects:
        p1 = base_rate
        p2 = p1 + effect
        z_a = 1.96  # alpha=0.05 双侧
        z_b = 0.842  # power=0.80
        pooled = p1 * (1-p1) + p2 * (1-p2)
        n = math.ceil((z_a + z_b) ** 2 * pooled / (effect ** 2))
        ref[f"+{effect*100:.0f}pp"] = f"{n:,}/组"
    return ref


def run():
    print("=" * 55)
    print("最小样本量计算器")
    print("=" * 55)

    print("\n【常用场景速查】")
    print("基准转化率 30% 时，不同提升幅度的最小样本量：")
    params = SampleSizeParams(control_rate=0.30, minimum_detectable_effect=0.03)
    result = calculate_sample_size(params)
    for lift, n in result["速查表参考"].items():
        print(f"  {lift}：{n}")

    print("\n【自定义计算】")
    params = SampleSizeParams(
        control_rate=0.30,
        minimum_detectable_effect=0.03,
        alpha=0.05,
        power=0.80,
    )
    result = calculate_sample_size(params)

    print(f"\n参数：")
    for k, v in result["参数"].items():
        print(f"  {k}：{v}")

    print(f"\n结果：")
    for k, v in result["计算结果"].items():
        print(f"  {k}：{v}")


if __name__ == "__main__":
    run()
```

---

## 案例库

### 案例1：多多买菜数据驱动的"爆品预测"

```
背景：多多买菜每天上架 2000+ SKU，无法靠人工选品

数据驱动选品体系：

Step 1：历史数据分析
  → 抓取拼多多平台同类商品的历史销量
  → 分析区域销量差异（哪些SKU在某城市卖得好）
  → 识别爆品规律：价格区间/品类/季节/促销节点

Step 2：实时供需匹配
  → 实时监控：各城市库存/销量/搜索量
  → 动态定价：供需紧张时自动提价，供过于求时自动降价
  → 爆品预测：基于实时数据，预测未来7天爆品

Step 3：爆品测试（小规模验证）
  → 新SKU先在10个团点试销
  → 24小时内根据销量决定：加量推广 or 下架

效果数据（2022年）：
  爆品命中率：78%（预测10个爆品，8个真爆）


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)