未记录事实核验 · 状态:现行内容

记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。

warning 适用边界与维护说明

本文适用于在给定参数和模型假设下学习二项分布计算、模拟、近似与统计推断;业务及医学参数均为教学设定,不构成实际效果证明。各次试验须独立且成功概率相同,有限批次不放回抽样、客户差异或患者异质性需另行判断模型适用性。正态与泊松近似条件是经验判断,尤其尾部概率应结合精确二项计算评估误差;营销案例的95%区间是给定成功率下成功次数的分布区间,而非成功率的置信区间。硬币案例的双尾概率写法限于当前对称零假设及观察值,不宜直接泛化到任意成功概率。医学部分仅示范历史成功率视为已知时的单侧检验,样本量结果限于50至490、步长10的搜索网格,不代表完整临床试验设计或临床有效性证明。本次仅作全文结构审阅,未运行代码或进行外部事实核验。

🎲 二项分布(Binomial Distribution)

abstract 📋 本节概览

🤔 什么是二项分布?

note 📖 **二项分布的定义**

二项分布描述了在n次独立的伯努利试验中,成功次数X的概率分布。每次试验只有两种可能结果:成功(概率p)或失败(概率1-p)。

记法:$X \sim B(n, p)$

概率质量函数: $$P(X = k) = \binom{n}{k} p^k (1-p)^{n-k}$$

其中:$\binom{n}{k} = \frac{n!}{k!(n-k)!}$

生活例子:

  • 投掷10次硬币,正面出现的次数
  • 100个产品中不合格品的数量
  • 向20个客户推销,成功销售的数量
  • 100次射击中命中靶心的次数

📊 二项分布的特征

1. 基本性质

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
from scipy.special import comb

def binomial_properties():
    """展示二项分布的基本性质"""
    
 # 参数设定
    n = 10  # 试验次数
    p = 0.3  # 成功概率
    
    print(f"二项分布 B({n}, {p}):")
    print("=" * 25)
    
 # 理论值
    mean_theory = n * p
    var_theory = n * p * (1 - p)
    std_theory = np.sqrt(var_theory)
    
    print(f"理论值:")
    print(f"  均值 E(X) = np = {n} × {p} = {mean_theory:.2f}")
    print(f"  方差 Var(X) = np(1-p) = {n} × {p} × {1-p} = {var_theory:.2f}")
    print(f"  标准差 SD(X) = √Var(X) = {std_theory:.2f}")
    
 # 使用scipy验证
    rv = stats.binom(n, p)
    mean_scipy = rv.mean()
    var_scipy = rv.var()
    std_scipy = rv.std()
    
    print(f"\nSciPy验证:")
    print(f"  均值: {mean_scipy:.2f}")
    print(f"  方差: {var_scipy:.2f}")
    print(f"  标准差: {std_scipy:.2f}")
    
 # 概率计算示例
    print(f"\n概率计算示例:")
    for k in [0, 1, 3, 5, 10]:
        prob_manual = comb(n, k) * (p**k) * ((1-p)**(n-k))
        prob_scipy = rv.pmf(k)
        print(f"  P(X = {k}) = {prob_manual:.4f} (手算) = {prob_scipy:.4f} (scipy)")
    
    return n, p, rv

n, p, rv = binomial_properties()

2. 形状特征

def plot_binomial_shapes():
    """绘制不同参数下的二项分布"""
    
    fig, axes = plt.subplots(2, 2, figsize=(12, 10))
    axes = axes.flatten()
    
 # 不同参数组合
    params = [
        (10, 0.1, "n=10, p=0.1 (右偏)"),
        (10, 0.5, "n=10, p=0.5 (对称)"),
        (10, 0.8, "n=10, p=0.8 (左偏)"),
        (30, 0.3, "n=30, p=0.3 (近似正态)")
    ]
    
    for i, (n, p, title) in enumerate(params):
        rv = stats.binom(n, p)
        k_values = np.arange(0, n+1)
        probabilities = rv.pmf(k_values)
        
 # 绘制概率质量函数
        axes[i].bar(k_values, probabilities, alpha=0.7, 
                   color=f'C{i}', edgecolor='black', linewidth=0.5)
        
 # 标注均值和标准差
        mean_val = rv.mean()
        std_val = rv.std()
        axes[i].axvline(mean_val, color='red', linestyle='--', 
                       label=f'μ={mean_val:.1f}')
        axes[i].axvline(mean_val - std_val, color='orange', linestyle=':', alpha=0.7)
        axes[i].axvline(mean_val + std_val, color='orange', linestyle=':', alpha=0.7)
        
        axes[i].set_title(title)
        axes[i].set_xlabel('成功次数 k')
        axes[i].set_ylabel('概率 P(X=k)')
        axes[i].legend()
        axes[i].grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()
    
 # 形状分析
    print("二项分布的形状特征:")
    print("=" * 25)
    print("• p = 0.5时,分布对称")
    print("• p < 0.5时,分布右偏")
    print("• p > 0.5时,分布左偏")
    print("• n增大时,分布趋近正态分布")

plot_binomial_shapes()

💻 Python实现

1. 基本计算

def binomial_calculations():
    """二项分布的各种计算"""
    
    n, p = 20, 0.3
    rv = stats.binom(n, p)
    
    print(f"二项分布 B({n}, {p}) 的计算:")
    print("=" * 30)
    
 # 1. 概率质量函数 (PMF)
    print("1. 概率质量函数:")
    for k in [0, 5, 6, 7, 10, 15, 20]:
        prob = rv.pmf(k)
        print(f"   P(X = {k:2d}) = {prob:.4f}")
    
 # 2. 累积分布函数 (CDF)
    print("\n2. 累积分布函数:")
    for k in [5, 6, 7, 10]:
        cdf_val = rv.cdf(k)
        print(f"   P(X ≤ {k:2d}) = {cdf_val:.4f}")
    
 # 3. 生存函数 (Survival Function)
    print("\n3. 生存函数:")
    for k in [5, 6, 7, 10]:
        sf_val = rv.sf(k)
        print(f"   P(X > {k:2d}) = {sf_val:.4f}")
    
 # 4. 分位数函数 (PPF)
    print("\n4. 分位数:")
    for percentile in [0.25, 0.5, 0.75, 0.9]:
        quantile = rv.ppf(percentile)
        print(f"   第{percentile*100:4.0f}百分位数: {quantile:.0f}")
    
 # 5. 区间概率
    print("\n5. 区间概率:")
    intervals = [(3, 7), (5, 10), (0, 5)]
    for a, b in intervals:
        prob_interval = rv.cdf(b) - rv.cdf(a-1)
        print(f"   P({a} ≤ X ≤ {b}) = {prob_interval:.4f}")
    
    return rv

rv = binomial_calculations()

2. 随机数生成和模拟

def binomial_simulation():
    """二项分布的模拟验证"""
    
    n, p = 15, 0.4
    n_simulations = 10000
    
    print(f"二项分布模拟验证:")
    print(f"参数: n={n}, p={p}")
    print(f"模拟次数: {n_simulations:,}")
    print("=" * 30)
    
 # 方法1: 使用numpy生成随机数
    np.random.seed(42)
    samples_numpy = np.random.binomial(n, p, n_simulations)
    
 # 方法2: 使用scipy生成随机数
    np.random.seed(42)
    rv = stats.binom(n, p)
    samples_scipy = rv.rvs(size=n_simulations)
    
 # 方法3: 手动模拟(通过多次伯努利试验)
    np.random.seed(42)
    samples_manual = []
    for _ in range(n_simulations):
 # 进行n次伯努利试验
        successes = np.sum(np.random.random(n) < p)
        samples_manual.append(successes)
    samples_manual = np.array(samples_manual)
    
 # 比较结果
    methods = ['NumPy', 'SciPy', '手动模拟']
    samples_list = [samples_numpy, samples_scipy, samples_manual]
    
 # 理论值
    theory_mean = n * p
    theory_var = n * p * (1 - p)
    theory_std = np.sqrt(theory_var)
    
    print(f"理论值: 均值={theory_mean:.2f}, 标准差={theory_std:.2f}")
    print("\n模拟结果比较:")
    print("方法\t\t均值\t标准差\t最小值\t最大值")
    print("-" * 50)
    
    for method, samples in zip(methods, samples_list):
        mean_sim = np.mean(samples)
        std_sim = np.std(samples, ddof=1)
        min_sim = np.min(samples)
        max_sim = np.max(samples)
        print(f"{method}\t\t{mean_sim:.2f}\t{std_sim:.2f}\t{min_sim}\t{max_sim}")
    
 # 可视化比较
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
    
 # 理论PMF vs 模拟频率
    k_values = np.arange(0, n+1)
    theory_pmf = rv.pmf(k_values)
    
 # 计算模拟频率 (使用NumPy结果)
    unique, counts = np.unique(samples_numpy, return_counts=True)
    sim_freq = counts / n_simulations
    
    ax1.bar(k_values - 0.2, theory_pmf, width=0.4, alpha=0.7, 
           label='理论PMF', color='blue')
    
 # 为模拟频率创建完整的数组
    sim_pmf = np.zeros(len(k_values))
    for val, freq in zip(unique, sim_freq):
        if val < len(sim_pmf):
            sim_pmf[val] = freq
    
    ax1.bar(k_values + 0.2, sim_pmf, width=0.4, alpha=0.7, 
           label='模拟频率', color='red')
    
    ax1.set_xlabel('成功次数 k')
    ax1.set_ylabel('概率/频率')
    ax1.set_title('理论vs模拟分布')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
 # Q-Q图检验
    from scipy import stats as scipy_stats
    scipy_stats.probplot(samples_numpy, dist=stats.binom(n, p), plot=ax2)
    ax2.set_title('Q-Q图: 模拟数据 vs 理论分布')
    ax2.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()
    
    return samples_numpy

samples = binomial_simulation()

🎯 实际应用案例

案例1:质量控制

def quality_control_case():
    """产品质量控制案例"""
    
    print("案例1: 产品质量控制")
    print("=" * 25)
    
 # 背景:某工厂生产的产品不合格率为5%
 # 随机抽检50件产品,分析不合格品数量
    
    n_products = 50  # 抽检数量
    defect_rate = 0.05  # 不合格率5%
    
    rv = stats.binom(n_products, defect_rate)
    
    print(f"问题设定:")
    print(f"  抽检产品数: {n_products}件")
    print(f"  不合格率: {defect_rate*100}%")
    print(f"  分布: X ~ B({n_products}, {defect_rate})")
    
 # 期望值
    expected_defects = rv.mean()
    std_defects = rv.std()
    
    print(f"\n统计特征:")
    print(f"  期望不合格品数: {expected_defects:.2f}件")
    print(f"  标准差: {std_defects:.2f}件")
    
 # 关键概率计算
    print(f"\n关键概率:")
    
 # 1. 没有不合格品的概率
    prob_zero = rv.pmf(0)
    print(f"  P(X = 0) = {prob_zero:.4f} ({prob_zero*100:.2f}%)")
    
 # 2. 最多2件不合格的概率
    prob_at_most_2 = rv.cdf(2)
    print(f"  P(X ≤ 2) = {prob_at_most_2:.4f} ({prob_at_most_2*100:.2f}%)")
    
 # 3. 超过5件不合格的概率(异常情况)
    prob_more_than_5 = rv.sf(5)
    print(f"  P(X > 5) = {prob_more_than_5:.4f} ({prob_more_than_5*100:.2f}%)")
    
 # 4. 控制限的设定(3σ原则)
    control_limit = expected_defects + 3 * std_defects
    prob_exceed_limit = rv.sf(int(control_limit))
    
    print(f"\n质量控制分析:")
    print(f"  控制上限 (μ + 3σ): {control_limit:.1f}件")
    print(f"  超过控制限概率: {prob_exceed_limit:.6f} ({prob_exceed_limit*10000:.2f}万分之一)")
    
 # 决策建议
    print(f"\n决策建议:")
    if prob_more_than_5 < 0.01:
        print(f"  如果发现超过5件不合格品(概率<1%),应调查生产过程")
    
 # 可视化
    k_values = np.arange(0, 15)
    probabilities = rv.pmf(k_values)
    
    plt.figure(figsize=(10, 6))
    plt.bar(k_values, probabilities, alpha=0.7, color='steelblue', edgecolor='black')
    plt.axvline(expected_defects, color='red', linestyle='--', linewidth=2, 
                label=f'期望值 = {expected_defects:.2f}')
    plt.axvline(control_limit, color='orange', linestyle='--', linewidth=2, 
                label=f'控制限 = {control_limit:.1f}')
    
    plt.xlabel('不合格品数量')
    plt.ylabel('概率')
    plt.title(f'不合格品数量分布 B({n_products}, {defect_rate})')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.show()

quality_control_case()

案例2:营销活动效果评估

def marketing_campaign_case():
    """营销活动效果评估案例"""
    
    print("\n\n案例2: 营销活动效果评估")
    print("=" * 30)
    
 # 背景:电话营销活动,历史成功率20%
 # 今天拨打了80个电话,分析成功销售数量
    
    n_calls = 80  # 拨打电话数
    success_rate = 0.20  # 成功率20%
    
    rv = stats.binom(n_calls, success_rate)
    
    print(f"营销活动设定:")
    print(f"  拨打电话数: {n_calls}个")
    print(f"  历史成功率: {success_rate*100}%")
    print(f"  分布: X ~ B({n_calls}, {success_rate})")
    
 # 统计特征
    expected_success = rv.mean()
    std_success = rv.std()
    
    print(f"\n预期结果:")
    print(f"  期望成功数: {expected_success:.1f}个")
    print(f"  标准差: {std_success:.2f}个")
    
 # 业务关键问题
    print(f"\n业务分析:")
    
 # 1. 至少完成15个销售的概率
    target_sales = 15
    prob_at_least_target = rv.sf(target_sales - 1)
    print(f"  P(X ≥ {target_sales}) = {prob_at_least_target:.4f} ({prob_at_least_target*100:.2f}%)")
    
 # 2. 90%把握下的最低成功数
    confidence_90 = rv.ppf(0.1)  # 10%分位数
    print(f"  90%把握下最低成功数: {confidence_90:.0f}个")
    
 # 3. 95%区间估计
    lower_95 = rv.ppf(0.025)
    upper_95 = rv.ppf(0.975)
    print(f"  95%区间: [{lower_95:.0f}, {upper_95:.0f}]个")
    
 # 4. 异常高效果的判断
    exceptional_threshold = expected_success + 2 * std_success
    prob_exceptional = rv.sf(int(exceptional_threshold))
    print(f"  超常发挥阈值 (μ + 2σ): {exceptional_threshold:.1f}个")
    print(f"  超常发挥概率: {prob_exceptional:.4f} ({prob_exceptional*100:.2f}%)")
    
 # ROI分析
    cost_per_call = 5  # 每通电话成本5元
    revenue_per_sale = 200  # 每次成功销售收入200元
    
    total_cost = n_calls * cost_per_call
    expected_revenue = expected_success * revenue_per_sale
    expected_profit = expected_revenue - total_cost
    expected_roi = (expected_profit / total_cost) * 100
    
    print(f"\nROI分析:")
    print(f"  总成本: {total_cost}元")
    print(f"  期望收入: {expected_revenue:.0f}元")
    print(f"  期望利润: {expected_profit:.0f}元")
    print(f"  期望ROI: {expected_roi:.1f}%")
    
 # 盈亏平衡分析
    breakeven_sales = total_cost / revenue_per_sale
    prob_breakeven = rv.sf(int(np.floor(breakeven_sales)))  # 严格盈利:成功销售数大于盈亏平衡点
    print(f"  盈亏平衡点: {breakeven_sales:.1f}个销售")
    print(f"  盈利概率: {prob_breakeven:.4f} ({prob_breakeven*100:.2f}%)")
    
 # 可视化结果
    k_values = np.arange(0, 35)
    probabilities = rv.pmf(k_values)
    
    plt.figure(figsize=(12, 6))
    plt.bar(k_values, probabilities, alpha=0.7, color='lightgreen', edgecolor='black')
    
 # 标注关键点
    plt.axvline(expected_success, color='blue', linestyle='-', linewidth=2, 
                label=f'期望值 = {expected_success:.1f}')
    plt.axvline(target_sales, color='red', linestyle='--', linewidth=2, 
                label=f'目标 = {target_sales}')
    plt.axvline(breakeven_sales, color='orange', linestyle=':', linewidth=2, 
                label=f'盈亏平衡 = {breakeven_sales:.1f}')
    
 # 填充区域
    k_success = k_values[k_values >= target_sales]
    prob_success = probabilities[k_values >= target_sales]
    plt.fill_between(k_success, 0, prob_success, alpha=0.3, color='red', 
                    label=f'达到目标区域')
    
    plt.xlabel('成功销售数量')
    plt.ylabel('概率')
    plt.title(f'营销活动成功数量分布 B({n_calls}, {success_rate})')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.show()

marketing_campaign_case()

案例3:医学试验设计

def medical_trial_case():
    """医学试验设计案例"""
    
    print("\n\n案例3: 医学试验设计")
    print("=" * 20)
    
 # 背景:新药治疗效果试验
 # 已知标准治疗成功率60%,新药预期成功率75%
    
    n_patients = 100  # 试验患者数
    standard_rate = 0.60  # 标准治疗成功率
    new_drug_rate = 0.75  # 新药预期成功率
    
    rv_standard = stats.binom(n_patients, standard_rate)
    rv_new_drug = stats.binom(n_patients, new_drug_rate)
    
    print(f"试验设计:")
    print(f"  患者数量: {n_patients}人")
    print(f"  标准治疗成功率: {standard_rate*100}%")
    print(f"  新药预期成功率: {new_drug_rate*100}%")
    
 # 统计特征比较
    print(f"\n预期结果比较:")
    print(f"  标准治疗: 期望{rv_standard.mean():.1f}人成功, 标准差{rv_standard.std():.2f}")
    print(f"  新药治疗: 期望{rv_new_drug.mean():.1f}人成功, 标准差{rv_new_drug.std():.2f}")
    
 # 试验成功标准设定
 # 假设患者结局独立、成功概率相同且历史基准0.60视为已知;成功人数超过基准分布的95%分位数时,拒绝H₀: p=0.60,支持H₁: p>0.60,但不据此单独认定临床有效性
    threshold = rv_standard.ppf(0.95)
    prob_new_drug_success = rv_new_drug.sf(int(threshold))
    
    print(f"\n试验成功标准:")
    print(f"  成功阈值: >{threshold:.0f}人")
    print(f"  新药达到标准的概率: {prob_new_drug_success:.4f} ({prob_new_drug_success*100:.2f}%)")
    
 # 检验力分析
 # 在α=0.05下,新药真实有效时被检出的概率
    alpha = 0.05
    critical_value = rv_standard.ppf(1 - alpha)
    power = rv_new_drug.sf(int(critical_value))
    
    print(f"\n检验力分析:")
    print(f"  显著性水平 α = {alpha}")
    print(f"  临界值: {critical_value:.0f}人")
    print(f"  检验力 (1-β): {power:.4f} ({power*100:.2f}%)")
    
 # 样本量计算(为达到80%检验力所需的样本量)
    def calculate_sample_size_for_power(target_power=0.8):
        """计算达到目标检验力所需的样本量"""
        for n in range(50, 500, 10):
            rv_std_n = stats.binom(n, standard_rate)
            rv_new_n = stats.binom(n, new_drug_rate)
            
            crit_val = rv_std_n.ppf(1 - alpha)
            power_n = rv_new_n.sf(int(crit_val))
            
            if power_n >= target_power:
                return n, power_n
        return None, None
    
    optimal_n, optimal_power = calculate_sample_size_for_power()
    print(f"\n样本量计算:")
    print(f"  在50至490、步长10的搜索网格中首次达到80%检验力的样本量: {optimal_n}人")
    print(f"  对应检验力: {optimal_power:.4f} ({optimal_power*100:.2f}%)")
    
 # 风险分析
 # 第一类错误:H₀: p=standard_rate成立时,成功人数仍落入拒绝域
    type1_error = rv_standard.sf(int(critical_value))
    
 # 第二类错误:新药实际有效,但未能检出差异
    type2_error = 1 - power
    
    print(f"\n风险分析:")
    print(f"  实际第一类错误率(名义α={alpha}): {type1_error:.3f} ({type1_error*100:.1f}%)")
    print(f"  第二类错误 (β): {type2_error:.3f} ({type2_error*100:.1f}%)")
    
 # 可视化两个分布
    k_values = np.arange(40, 90)
    prob_standard = rv_standard.pmf(k_values)
    prob_new_drug = rv_new_drug.pmf(k_values)
    
    plt.figure(figsize=(12, 6))
    plt.bar(k_values - 0.2, prob_standard, width=0.4, alpha=0.7, 
           label=f'标准治疗 B({n_patients}, {standard_rate})', color='blue')
    plt.bar(k_values + 0.2, prob_new_drug, width=0.4, alpha=0.7, 
           label=f'新药治疗 B({n_patients}, {new_drug_rate})', color='red')
    
    plt.axvline(critical_value, color='black', linestyle='--', linewidth=2, 
                label=f'临界值 = {critical_value:.0f}')
    
 # 填充检验力区域
    k_power = k_values[k_values > critical_value]
    prob_power = rv_new_drug.pmf(k_power)
    plt.fill_between(k_power + 0.2, 0, prob_power, alpha=0.3, color='green', 
                    label=f'检验力区域')
    
    plt.xlabel('成功治疗人数')
    plt.ylabel('概率')
    plt.title('医学试验:标准治疗 vs 新药治疗')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.show()

medical_trial_case()

🔄 二项分布的近似

1. 正态近似

def normal_approximation():
    """二项分布的正态近似"""
    
    print("\n\n二项分布的正态近似:")
    print("=" * 25)
    
 # 大样本情况
    n = 100
    p = 0.3
    
    rv_binom = stats.binom(n, p)
    
 # 正态近似参数
    mu = n * p
    sigma = np.sqrt(n * p * (1 - p))
    rv_normal = stats.norm(mu, sigma)
    
    print(f"原分布: B({n}, {p})")
    print(f"正态近似: N({mu:.1f}, {sigma:.2f}²)")
    
 # 近似条件检查
    print(f"\n近似条件检查:")
    print(f"  np = {n*p:.1f} ≥ 5? {'是' if n*p >= 5 else '否'}")
    print(f"  n(1-p) = {n*(1-p):.1f} ≥ 5? {'是' if n*(1-p) >= 5 else '否'}")
    
 # 比较概率计算
    test_values = [25, 30, 35, 40]
    print(f"\n概率比较:")
    print("k\t二项分布\t正态近似\t连续性校正\t误差")
    print("-" * 60)
    
    for k in test_values:
 # 精确二项概率
        prob_exact = rv_binom.pmf(k)
        
 # 正态近似(不校正)
        prob_normal = rv_normal.pdf(k)
        
 # 连续性校正
        prob_corrected = rv_normal.cdf(k + 0.5) - rv_normal.cdf(k - 0.5)
        
        error = abs(prob_exact - prob_corrected)
        
        print(f"{k}\t{prob_exact:.6f}\t{prob_normal:.6f}\t{prob_corrected:.6f}\t{error:.6f}")
    
 # 累积概率比较
    print(f"\n累积概率比较 P(X ≤ k):")
    print("k\t二项分布\t正态近似\t连续性校正\t误差")
    print("-" * 60)
    
    for k in test_values:
 # 精确累积概率
        cdf_exact = rv_binom.cdf(k)
        
 # 正态近似(不校正)
        cdf_normal = rv_normal.cdf(k)
        
 # 连续性校正
        cdf_corrected = rv_normal.cdf(k + 0.5)
        
        error = abs(cdf_exact - cdf_corrected)
        
        print(f"{k}\t{cdf_exact:.6f}\t{cdf_normal:.6f}\t{cdf_corrected:.6f}\t{error:.6f}")
    
 # 可视化比较
    k_values = np.arange(15, 50)
    prob_binom = rv_binom.pmf(k_values)
    
 # 正态密度(连续)
    x_continuous = np.linspace(15, 50, 200)
    density_normal = rv_normal.pdf(x_continuous)
    
 # 正态近似(离散化)
    prob_normal_discrete = rv_normal.pdf(k_values)
    
    plt.figure(figsize=(12, 6))
    
 # 二项分布
    plt.bar(k_values, prob_binom, alpha=0.7, color='blue', 
           label=f'二项分布 B({n}, {p})', edgecolor='black', linewidth=0.5)
    
 # 正态近似(连续)
    plt.plot(x_continuous, density_normal, 'r-', linewidth=2, 
            label=f'正态近似 N({mu:.1f}, {sigma:.2f}²)')
    
 # 正态近似(离散点)
    plt.scatter(k_values, prob_normal_discrete, color='red', s=20, alpha=0.7)
    
    plt.xlabel('k')
    plt.ylabel('概率/密度')
    plt.title('二项分布的正态近似')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.show()
    
    print(f"\n💡 使用建议:")
    print(f"- 当np ≥ 5且n(1-p) ≥ 5时,正态近似效果较好")
    print(f"- 计算累积概率时使用连续性校正:P(X ≤ k) ≈ Φ((k+0.5-μ)/σ)")
    print(f"- p接近0.5时近似效果最好")

normal_approximation()

2. 泊松近似

def poisson_approximation():
    """二项分布的泊松近似"""
    
    print("\n\n二项分布的泊松近似:")
    print("=" * 25)
    
 # 大n小p的情况
    n = 1000
    p = 0.003
    lambda_param = n * p
    
    rv_binom = stats.binom(n, p)
    rv_poisson = stats.poisson(lambda_param)
    
    print(f"原分布: B({n}, {p})")
    print(f"泊松近似: Poisson({lambda_param})")
    
 # 近似条件检查
    print(f"\n近似条件检查:")
    print(f"  n = {n} (大)")
    print(f"  p = {p} (小)")
    print(f"  λ = np = {lambda_param} (适中)")
    
 # 比较概率
    test_values = [0, 1, 2, 3, 4, 5, 6, 7, 8]
    print(f"\n概率比较 P(X = k):")
    print("k\t二项分布\t泊松近似\t误差")
    print("-" * 40)
    
    for k in test_values:
        prob_binom = rv_binom.pmf(k)
        prob_poisson = rv_poisson.pmf(k)
        error = abs(prob_binom - prob_poisson)
        
        print(f"{k}\t{prob_binom:.6f}\t{prob_poisson:.6f}\t{error:.6f}")
    
 # 累积概率比较
    print(f"\n累积概率比较 P(X ≤ k):")
    print("k\t二项分布\t泊松近似\t误差")
    print("-" * 40)
    
    for k in test_values:
        cdf_binom = rv_binom.cdf(k)
        cdf_poisson = rv_poisson.cdf(k)
        error = abs(cdf_binom - cdf_poisson)
        
        print(f"{k}\t{cdf_binom:.6f}\t{cdf_poisson:.6f}\t{error:.6f}")
    
 # 可视化比较
    k_range = np.arange(0, 15)
    prob_binom = rv_binom.pmf(k_range)
    prob_poisson = rv_poisson.pmf(k_range)
    
    plt.figure(figsize=(12, 6))
    
    width = 0.35
    plt.bar(k_range - width/2, prob_binom, width, alpha=0.7, 
           label=f'二项分布 B({n}, {p})', color='blue')
    plt.bar(k_range + width/2, prob_poisson, width, alpha=0.7, 
           label=f'泊松近似 Poisson({lambda_param})', color='red')
    
    plt.xlabel('k')
    plt.ylabel('概率')
    plt.title('二项分布的泊松近似 (大n小p情况)')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.show()
    
    print(f"\n💡 使用条件:")
    print(f"- n很大 (通常n ≥ 100)")
    print(f"- p很小 (通常p ≤ 0.01)")
    print(f"- np适中 (通常np < 10)")
    print(f"- 经验法则: n ≥ 100, p ≤ 0.01, np ≤ 10")

poisson_approximation()

🛠️ 实用技巧和最佳实践

1. 参数估计

def parameter_estimation():
    """二项分布参数估计"""
    
    print("\n\n二项分布参数估计:")
    print("=" * 20)
    
 # 模拟真实情况:已知试验次数n,估计成功概率p
    true_n = 50
    true_p = 0.35
    
 # 生成观察数据
    np.random.seed(42)
    observed_successes = np.random.binomial(true_n, true_p, 100)  # 100次实验
    
    print(f"真实参数: n = {true_n}, p = {true_p}")
    print(f"观察数据: 100次实验,每次{true_n}次试验")
    
 # 最大似然估计
    sample_mean = np.mean(observed_successes)
    p_hat = sample_mean / true_n  # MLE估计
    
    print(f"\n参数估计:")
    print(f"  样本均值: {sample_mean:.2f}")
    print(f"  p的MLE估计: {p_hat:.4f}")
    print(f"  估计误差: {abs(p_hat - true_p):.4f}")
    
 # 置信区间(正态近似)
    total_trials = true_n * len(observed_successes)
    se_p = np.sqrt(p_hat * (1 - p_hat) / total_trials)  # 全部独立试验下的标准误
    confidence_level = 0.95
    z_alpha = stats.norm.ppf(1 - (1 - confidence_level)/2)
    
    ci_lower = p_hat - z_alpha * se_p
    ci_upper = p_hat + z_alpha * se_p
    
    print(f"\n95%置信区间:")
    print(f"  [{ci_lower:.4f}, {ci_upper:.4f}]")
    print(f"  真实值在区间内: {'是' if ci_lower <= true_p <= ci_upper else '否'}")
    
 # Wilson置信区间(更准确)
    def wilson_confidence_interval(x, n, confidence=0.95):
        """Wilson置信区间"""
        z = stats.norm.ppf(1 - (1 - confidence)/2)
        p_tilde = (x + z**2/2) / (n + z**2)
        margin = z / (1 + z**2 / n) * np.sqrt((x / n) * (1 - x / n) / n + z**2 / (4 * n**2))
        return p_tilde - margin, p_tilde + margin
    
    wilson_lower, wilson_upper = wilson_confidence_interval(np.sum(observed_successes), total_trials)
    print(f"\nWilson 95%置信区间:")
    print(f"  [{wilson_lower:.4f}, {wilson_upper:.4f}]")
    print(f"  真实值在区间内: {'是' if wilson_lower <= true_p <= wilson_upper else '否'}")

parameter_estimation()

2. 假设检验应用

def binomial_hypothesis_test():
    """二项分布假设检验"""
    
    print("\n\n二项分布假设检验:")
    print("=" * 20)
    
 # 案例:检验硬币是否公平
    n_tosses = 100  # 投掷次数
    observed_heads = 58  # 观察到的正面次数
    null_p = 0.5  # 原假设:硬币公平
    
    print(f"案例: 硬币公平性检验")
    print(f"  投掷次数: {n_tosses}")
    print(f"  观察正面: {observed_heads}次")
    print(f"  H₀: p = {null_p} (硬币公平)")
    print(f"  H₁: p ≠ {null_p} (硬币不公平)")
    
 # 方法1: 精确二项检验
    p_value_exact = 2 * min(stats.binom.cdf(observed_heads, n_tosses, null_p),
                           stats.binom.sf(observed_heads - 1, n_tosses, null_p))
    
    print(f"\n精确二项检验:")
    print(f"  p值: {p_value_exact:.4f}")
    
 # 方法2: 正态近似检验(连续性校正)
    expected = n_tosses * null_p
    variance = n_tosses * null_p * (1 - null_p)
    std_error = np.sqrt(variance)
    
 # 连续性校正
    if observed_heads > expected:
        z_stat = (observed_heads - 0.5 - expected) / std_error
    else:
        z_stat = (observed_heads + 0.5 - expected) / std_error
    
    p_value_normal = 2 * (1 - stats.norm.cdf(abs(z_stat)))
    
    print(f"\n正态近似检验 (连续性校正):")
    print(f"  期望值: {expected}")
    print(f"  标准误: {std_error:.2f}")
    print(f"  z统计量: {z_stat:.3f}")
    print(f"  p值: {p_value_normal:.4f}")
    
 # 决策
    alpha = 0.05
    print(f"\n检验结论 (α = {alpha}):")
    if p_value_exact < alpha:
        print(f"  拒绝原假设 (p = {p_value_exact:.4f} < {alpha})")
        print(f"  结论: 在独立同分布投掷假设下,有统计证据支持硬币正面概率不等于0.5")
    else:
        print(f"  不拒绝原假设 (p = {p_value_exact:.4f} ≥ {alpha})")
        print(f"  结论: 没有足够证据表明硬币不公平")
    
 # 置信区间
    from statsmodels.stats.proportion import proportion_confint
    ci_lower, ci_upper = proportion_confint(observed_heads, n_tosses, alpha=0.05)
    
    print(f"\n观察比例的95%置信区间:")
    print(f"  观察比例: {observed_heads/n_tosses:.3f}")
    print(f"  置信区间: [{ci_lower:.3f}, {ci_upper:.3f}]")
    print(f"  0.5在区间内: {'是' if ci_lower <= 0.5 <= ci_upper else '否'}")

binomial_hypothesis_test()

🔗 相关知识

#统计学 #二项分布 #概率分布 #离散分布 #伯努利试验 #基础