未记录事实核验 · 状态:维护中

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

warning 适用边界与维护说明

本文适合学习峰度与超额峰度计算、模拟分布比较、Bootstrap、峰度检验及滑窗监控的实现,不是已校准的投资或生产决策工具。当前类型可视化和分析工具包仍根据峰度输出“尖峭/平坦”“厚尾/薄尾”等标签,不能据此确定峰顶形状或指定阈值处的尾部概率;两处检验输出的“接受正态峰度假设”应理解为未拒绝,不能视为证实零假设或正态性。df=3、df=4的t分布没有有限总体四阶矩,相关有限样本峰度及Bootstrap区间不能作为有限总体峰度的稳定估计;df=5示例的Bootstrap区间也没有覆盖率保证。金融资产、工艺名称及风险等级仅为模拟设定,峰度排序和示例建议不能证明资产安全、配置合理、过程稳定或精度不足,非正态过程的Cp/Cpk不能直接解释为正态尾部风险或能力等级。滑窗阈值和质量监控控制限未提供误报率校准,监控状态仅表示示例规则的判定结果。代码依赖首段导入,应按正文顺序使用;本次仅作全文结构审阅,未运行代码或进行外部事实核验。

📈 峰度(Kurtosis)

abstract 📋 本节概览

  • 🎯 学习目标:掌握峰度的概念、计算和实际应用
  • 📚 前置知识:描述性统计|描述性统计 | 正态分布|正态分布 | 偏度|偏度
  • ⏱️ 预计用时:8分钟

🤔 什么是峰度?

note 📖 **峰度的定义**

峰度是标准化四阶中心矩,在方差非零且四阶中心矩有限时定义,反映标准化偏差的四次方的平均大小,对极端值十分敏感;它不能单独确定峰顶尖峭程度、正态性或某个阈值处的尾部概率。

数学表达式: $$\text{Kurtosis} = \frac{E[(X-\mu)^4]}{\sigma^4} = \frac{\mu_4}{\sigma^4}$$

其中:

  • $\mu_4$ 是四阶中心矩
  • $\sigma$ 是标准差
  • $E[·]$ 表示期望值

超额峰度(Excess Kurtosis): $$\text{Excess Kurtosis} = \text{Kurtosis} - 3$$

峰度值的含义:

  • 峰度 = 3(超额峰度 = 0):与正态分布的峰度相同(mesokurtic),不意味着分布正态
  • 峰度 > 3(超额峰度 > 0):高峰度(leptokurtic),标准化四阶矩高于正态参考值
  • 峰度 < 3(超额峰度 < 0):低峰度(platykurtic),标准化四阶矩低于正态参考值

这些分类不能单独确定峰顶形状或任意指定阈值处的尾部概率。

生活例子:

  • 股票收益率:通常具有高峰度,极端收益比正态分布更频繁
  • 测量误差:可能呈现低峰度,误差分布相对均匀
  • 考试成绩:成绩集中并不必然意味着高峰度;若多数成绩集中而少数成绩远离均值,可能出现较高峰度,需按实际分布计算。
  • 身高体重:接近正态峰度

📊 峰度的类型与特征

1. 三种峰度类型

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import seaborn as sns

def plot_kurtosis_types():
    """展示不同类型的峰度"""
    fig, ((ax1, ax2, ax3), (ax4, ax5, ax6)) = plt.subplots(2, 3, figsize=(18, 12))
    
    np.random.seed(42)
    
 # 1. 正态峰度 (mesokurtic) - 峰度 = 3
    normal_data = np.random.normal(0, 1, 5000)
    normal_kurt = stats.kurtosis(normal_data, fisher=False)  # 原始峰度
    normal_excess_kurt = stats.kurtosis(normal_data, fisher=True)  # 超额峰度
    
    ax1.hist(normal_data, bins=50, density=True, alpha=0.7, color='blue', edgecolor='black')
    ax1.set_title(f'正态峰度 (Mesokurtic)\n峰度 = {normal_kurt:.2f}, 超额峰度 = {normal_excess_kurt:.2f}')
    ax1.set_ylabel('密度')
    ax1.grid(True, alpha=0.3)
    
 # 叠加理论正态分布
    x_range = np.linspace(-4, 4, 1000)
    ax1.plot(x_range, stats.norm.pdf(x_range, 0, 1), 'r-', linewidth=2, label='理论正态分布')
    ax1.legend()
    
 # 2. 高峰度 (leptokurtic) - 峰度 > 3
 # 使用t分布(自由度较小)模拟高峰度
    high_kurt_data = stats.t.rvs(df=3, size=5000)  # t分布,df=3
    high_kurt = stats.kurtosis(high_kurt_data, fisher=False)
    high_excess_kurt = stats.kurtosis(high_kurt_data, fisher=True)
    
    ax2.hist(high_kurt_data, bins=50, density=True, alpha=0.7, color='red', 
            edgecolor='black', range=(-5, 5))
    ax2.set_title(f'高峰度 (Leptokurtic)\n峰度 = {high_kurt:.2f}, 超额峰度 = {high_excess_kurt:.2f}')
    ax2.grid(True, alpha=0.3)
    
 # 对比正态分布
    ax2.plot(x_range, stats.norm.pdf(x_range, 0, 1), 'b--', alpha=0.7, 
            linewidth=2, label='正态分布对比')
    ax2.legend()
    
 # 3. 低峰度 (platykurtic) - 峰度 < 3
 # 使用均匀分布模拟低峰度
    low_kurt_data = np.random.uniform(-2, 2, 5000)
    low_kurt = stats.kurtosis(low_kurt_data, fisher=False)
    low_excess_kurt = stats.kurtosis(low_kurt_data, fisher=True)
    
    ax3.hist(low_kurt_data, bins=50, density=True, alpha=0.7, color='green', edgecolor='black')
    ax3.set_title(f'低峰度 (Platykurtic)\n峰度 = {low_kurt:.2f}, 超额峰度 = {low_excess_kurt:.2f}')
    ax3.grid(True, alpha=0.3)
    
 # 对比正态分布
    x_uniform = np.linspace(-2.5, 2.5, 1000)
    ax3.plot(x_uniform, stats.norm.pdf(x_uniform, 0, 1.15), 'b--', alpha=0.7, 
            linewidth=2, label='调整的正态分布')
    ax3.legend()
    
 # 4-6. 尾部对比图(对数尺度)
    datasets = [
        ("正态分布", normal_data, 'blue'),
        ("高峰度分布", high_kurt_data, 'red'),
        ("低峰度分布", low_kurt_data, 'green')
    ]
    
    axes_bottom = [ax4, ax5, ax6]
    
    for i, (name, data, color) in enumerate(datasets):
 # 使用完整样本的绝对值排序,避免截断尾部;此处比较原始尺度
        abs_data = np.sort(np.abs(data))
        n = len(abs_data)
        tail_prob = (n - np.searchsorted(abs_data, abs_data, side='right')) / n
        
 # 绘制经验双尾概率(保留概率大于1e-4的点)
        tail_mask = tail_prob > 1e-4
        if np.sum(tail_mask) > 10:  # 确保有足够的点
            axes_bottom[i].semilogy(abs_data[tail_mask], tail_prob[tail_mask], 
                                   'o-', color=color, markersize=3, alpha=0.7, label=name)
        
 # 对比理论正态分布的尾部
        x_tail = np.linspace(0, 4, 100)
        normal_tail = 2 * (1 - stats.norm.cdf(x_tail))  # 双尾概率
        axes_bottom[i].semilogy(x_tail, normal_tail, 'k--', alpha=0.7, 
                               linewidth=2, label='正态分布理论值')
        
        axes_bottom[i].set_xlabel('|x|')
        axes_bottom[i].set_ylabel('P(|X| > x)')
        axes_bottom[i].set_title(f'{name} - 尾部概率')
        axes_bottom[i].legend()
        axes_bottom[i].grid(True, alpha=0.3)
        axes_bottom[i].set_ylim(1e-4, 1)
    
    plt.tight_layout()
    plt.show()
    
 # 数值比较
    print("峰度类型数值对比:")
    print("=" * 50)
    
    datasets_analysis = [
        ("正态分布", normal_data),
        ("高峰度分布 (t分布, df=3)", high_kurt_data),
        ("低峰度分布 (均匀分布)", low_kurt_data)
    ]
    
    print(f"{'分布类型':<25} {'峰度':<8} {'超额峰度':<10} {'特征描述':<20}")
    print("-" * 70)
    
    for name, data in datasets_analysis:
        kurt_val = stats.kurtosis(data, fisher=False)
        excess_kurt = stats.kurtosis(data, fisher=True)
        
        if abs(excess_kurt) < 0.5:
            description = "峰度接近正态参考值,不代表分布正态"
        elif excess_kurt > 2:
            description = "高度尖峭,厚尾"
        elif excess_kurt > 0:
            description = "轻度尖峭,较厚尾"
        elif excess_kurt < -1:
            description = "高度平坦,薄尾"
        else:
            description = "轻度平坦,较薄尾"
        
        print(f"{name:<25} {kurt_val:<8.2f} {excess_kurt:<10.2f} {description:<20}")
    
 # 尾部风险分析
    print(f"\n尾部风险对比 (|x| > 2的概率):")
    print("-" * 35)
    
    for name, data in datasets_analysis:
        tail_prob = np.mean(np.abs(data) > 2)
        theoretical_normal_tail = 2 * (1 - stats.norm.cdf(2))  # 理论正态分布
        
        print(f"{name:<25}: {tail_prob:.4f} (正态分布: {theoretical_normal_tail:.4f})")

plot_kurtosis_types()

2. 峰度的计算方法

def calculate_kurtosis_methods():
    """演示峰度的不同计算方法"""
    np.random.seed(42)
    
 # 生成高峰度数据 (t分布)
    data = stats.t.rvs(df=5, size=1000)
    
    print("峰度的计算方法:")
    print("=" * 40)
    
 # 1. 手动计算 - 第四中心矩方法
    n = len(data)
    mean = np.mean(data)
    std = np.std(data, ddof=0)  # 与第四中心矩及SciPy默认bias=True使用一致的矩估计口径
    
 # 第四中心矩
    fourth_moment = np.mean((data - mean)**4)
    kurt_manual = fourth_moment / (std**4)
    excess_kurt_manual = kurt_manual - 3
    
    print(f"1. 手动计算(第四中心矩法):")
    print(f"   均值: {mean:.4f}")
    print(f"   标准差: {std:.4f}")
    print(f"   第四中心矩: {fourth_moment:.4f}")
    print(f"   峰度: {kurt_manual:.4f}")
    print(f"   超额峰度: {excess_kurt_manual:.4f}")
    
 # 2. scipy.stats 计算(两种定义)
 # Fisher定义(超额峰度)
    fisher_kurt = stats.kurtosis(data, fisher=True)
 # Pearson定义(原始峰度)
    pearson_kurt = stats.kurtosis(data, fisher=False)
    
    print(f"\n2. SciPy统计函数:")
    print(f"   Fisher定义(超额峰度): {fisher_kurt:.4f}")
    print(f"   Pearson定义(原始峰度): {pearson_kurt:.4f}")
    print(f"   验证关系: {pearson_kurt:.4f} = {fisher_kurt:.4f} + 3")
    
 # 3. 矩估计vs样本估计
 # 使用不同的标准化方法
    kurt_biased = stats.kurtosis(data, fisher=True, bias=True)
    kurt_unbiased = stats.kurtosis(data, fisher=True, bias=False)
    
    print(f"\n3. 偏差修正:")
    print(f"   有偏估计: {kurt_biased:.4f}")
    print(f"   偏差修正估计(非任意分布下严格无偏): {kurt_unbiased:.4f}")
    
 # 4. 峰度的置信区间(Bootstrap方法)
    n_bootstrap = 1000
    bootstrap_kurts = []
    
    for _ in range(n_bootstrap):
        bootstrap_sample = np.random.choice(data, size=len(data), replace=True)
        bootstrap_kurts.append(stats.kurtosis(bootstrap_sample, fisher=True))
    
    kurt_ci_lower = np.percentile(bootstrap_kurts, 2.5)
    kurt_ci_upper = np.percentile(bootstrap_kurts, 97.5)
    
    print(f"\n4. 超额峰度的95%置信区间 (Bootstrap):")
    print(f"   [{kurt_ci_lower:.4f}, {kurt_ci_upper:.4f}]")
    
 # 5. 峰度的稳健性分析
    print(f"\n5. 峰度对异常值的敏感性:")
    
 # 原始数据
    original_kurt = stats.kurtosis(data, fisher=True)
    
 # 添加异常值
    outlier_data = np.append(data, [10, -10])  # 添加两个极端值
    outlier_kurt = stats.kurtosis(outlier_data, fisher=True)
    
    print(f"   原始数据峰度: {original_kurt:.4f}")
    print(f"   添加异常值后: {outlier_kurt:.4f}")
    print(f"   变化幅度: {outlier_kurt - original_kurt:.4f}")
    
 # 6. 样本量对峰度估计的影响
    print(f"\n6. 样本量对峰度估计的影响:")
    
 # 真实分布参数
    true_data = stats.t.rvs(df=5, size=10000)
    true_kurt = 6.0  # t分布df=5的理论超额峰度;true_data仅为重复抽样所用的有限模拟样本池
    
    sample_sizes = [50, 100, 500, 1000, 5000]
    
    print(f"   真实超额峰度: {true_kurt:.4f}")
    print("   样本量 -> 平均估计超额峰度 (固定模拟样本池内不放回重复抽样的标准差)")
    
    for size in sample_sizes:
        sample_kurts = []
        for _ in range(100):  # 100次重复采样
            sample = np.random.choice(true_data, size=size, replace=False)
            sample_kurts.append(stats.kurtosis(sample, fisher=True))
        
        mean_kurt = np.mean(sample_kurts)
        std_kurt = np.std(sample_kurts, ddof=1)
        
        print(f"   {size:4d} -> {mean_kurt:.4f} ({std_kurt:.4f})")
    
 # 7. 不同分布的理论峰度
    print(f"\n7. 常见分布的理论峰度:")
    
    theoretical_kurtosis = {
        "正态分布": 0,  # 超额峰度
        "均匀分布": -1.2,
        "指数分布": 6,
        "拉普拉斯分布": 3,
        "t分布(df=3)": float('inf') if 3 <= 4 else 6/(3-4),  # df=3时峰度无穷
        "t分布(df=5)": 6/(5-4) if 5 > 4 else float('inf')
    }
    
    for dist_name, theoretical_val in theoretical_kurtosis.items():
        if dist_name == "t分布(df=5)":
            theoretical_val = 6  # df=5时的超额峰度
        print(f"   {dist_name}: {theoretical_val}")

calculate_kurtosis_methods()

💻 Python实现

1. 峰度分析工具包

def kurtosis_analysis_toolkit():
    """峰度分析的完整工具包"""
    
    def analyze_kurtosis(data, name="数据"):
        """分析数据的峰度"""
 # 基本统计量
        mean_val = np.mean(data)
        std_val = np.std(data, ddof=1)
        kurt_val = stats.kurtosis(data, fisher=False)  # 原始峰度
        excess_kurt = stats.kurtosis(data, fisher=True)  # 超额峰度
        
 # 峰度解释
        if abs(excess_kurt) < 0.5:
            kurt_desc = "接近正态峰度"
            color = 'blue'
        elif excess_kurt > 2:
            kurt_desc = "高度尖峭分布"
            color = 'red'
        elif excess_kurt > 0:
            kurt_desc = "中度尖峭分布"
            color = 'orange'
        elif excess_kurt < -1:
            kurt_desc = "高度平坦分布"
            color = 'lightgreen'
        else:
            kurt_desc = "中度平坦分布"
            color = 'green'
        
 # 尾部风险评估
        tail_2sigma = np.mean(np.abs(data - mean_val) > 2 * std_val)
        normal_tail_2sigma = 2 * (1 - stats.norm.cdf(2))
        tail_risk_ratio = tail_2sigma / normal_tail_2sigma if normal_tail_2sigma > 0 else 1
        
        print(f"{name}峰度分析:")
        print("-" * 30)
        print(f"样本量: {len(data)}")
        print(f"均值: {mean_val:.4f}")
        print(f"标准差: {std_val:.4f}")
        print(f"峰度: {kurt_val:.4f}")
        print(f"超额峰度: {excess_kurt:.4f}")
        print(f"峰度类型: {kurt_desc}")
        print(f"2σ外概率: {tail_2sigma:.4f} (正态分布: {normal_tail_2sigma:.4f})")
        print(f"尾部风险倍数: {tail_risk_ratio:.2f}x")
        
        return {
            'mean': mean_val,
            'std': std_val,
            'kurtosis': kurt_val,
            'excess_kurtosis': excess_kurt,
            'description': kurt_desc,
            'color': color,
            'tail_risk_ratio': tail_risk_ratio
        }
    
    def plot_kurtosis_analysis(data, name="数据", ax=None):
        """绘制峰度分析图"""
        if ax is None:
            fig, ax = plt.subplots(1, 1, figsize=(10, 6))
        
 # 分析峰度
        result = analyze_kurtosis(data, name)
        
 # 绘制直方图
        ax.hist(data, bins=50, density=True, alpha=0.7, 
               color=result['color'], edgecolor='black')
        
 # 叠加正态分布对比
        x_range = np.linspace(data.min(), data.max(), 100)
        normal_fit = stats.norm.pdf(x_range, result['mean'], result['std'])
        ax.plot(x_range, normal_fit, 'k--', linewidth=2, alpha=0.8, 
               label='正态分布拟合')
        
 # 标注统计量
        ax.axvline(result['mean'], color='red', linestyle='-', 
                  linewidth=2, label=f"均值 = {result['mean']:.2f}")
        
 # 标注±2σ范围
        ax.axvline(result['mean'] - 2*result['std'], color='orange', 
                  linestyle=':', linewidth=1, alpha=0.7, label='±2σ')
        ax.axvline(result['mean'] + 2*result['std'], color='orange', 
                  linestyle=':', linewidth=1, alpha=0.7)
        
        ax.set_title(f'{name} - {result["description"]}\n' + 
                    f'超额峰度 = {result["excess_kurtosis"]:.3f}, ' +
                    f'尾部风险 = {result["tail_risk_ratio"]:.1f}x')
        ax.set_xlabel('值')
        ax.set_ylabel('密度')
        ax.legend()
        ax.grid(True, alpha=0.3)
        
        return result
    
    def compare_tail_behavior(datasets):
        """比较不同数据集的尾部行为"""
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
        
        colors = plt.cm.Set1(np.linspace(0, 1, len(datasets)))
        
        for i, (name, data, color) in enumerate(zip(datasets.keys(), datasets.values(), colors)):
 # 标准化数据
            standardized = (data - np.mean(data)) / np.std(data, ddof=1)
            
 # 计算经验分布
            sorted_abs = np.sort(np.abs(standardized))
            n = len(sorted_abs)
            survival_prob = (n - np.searchsorted(sorted_abs, sorted_abs, side='right')) / n
            
 # Q-Q图 vs 正态分布
            theoretical_quantiles = stats.norm.ppf((np.arange(1, len(data) + 1) - 0.5) / len(data))
            sample_quantiles = np.sort(standardized)
            
            ax1.scatter(theoretical_quantiles, sample_quantiles, alpha=0.6, 
                       color=color, s=10, label=name)
            
 # 尾部概率图
            mask = survival_prob > 1e-4
            if np.sum(mask) > 10:
                ax2.semilogy(sorted_abs[mask], survival_prob[mask], 
                           'o-', color=color, markersize=3, alpha=0.7, label=name)
        
 # Q-Q图设置
        ax1.plot([-4, 4], [-4, 4], 'k--', alpha=0.5, label='理论直线')
        ax1.set_xlabel('理论分位数')
        ax1.set_ylabel('样本分位数')
        ax1.set_title('Q-Q图 vs 标准正态分布')
        ax1.legend()
        ax1.grid(True, alpha=0.3)
        
 # 尾部概率图设置
        x_theory = np.linspace(0, 4, 100)
        normal_tail = 2 * (1 - stats.norm.cdf(x_theory))
        ax2.semilogy(x_theory, normal_tail, 'k--', linewidth=2, 
                    alpha=0.7, label='标准正态分布')
        ax2.set_xlabel('|标准化值|')
        ax2.set_ylabel('P(|X| > x)')
        ax2.set_title('尾部概率对比')
        ax2.legend()
        ax2.grid(True, alpha=0.3)
        ax2.set_ylim(1e-4, 1)
        
        plt.tight_layout()
        plt.show()
    
 # 演示工具包应用
    print("峰度分析工具包演示:")
    print("=" * 50)
    
 # 生成不同峰度的示例数据
    np.random.seed(42)
    
    datasets = {
        "正态分布": np.random.normal(0, 1, 2000),
        "t分布(df=3)": stats.t.rvs(df=3, size=2000),
        "均匀分布": np.random.uniform(-2, 2, 2000),
        "拉普拉斯分布": stats.laplace.rvs(size=2000),
        "混合分布": np.concatenate([
            np.random.normal(0, 0.5, 1600),  # 主体分布
            np.random.normal(0, 3, 400)      # 厚尾分量
        ])
    }
    
 # 分析每个数据集
    fig, axes = plt.subplots(2, 3, figsize=(18, 12))
    axes = axes.flatten()
    
    results = {}
    for i, (name, data) in enumerate(datasets.items()):
        if i < len(axes):
            print(f"\n{i+1}. {name}:")
            result = plot_kurtosis_analysis(data, name, axes[i])
            results[name] = result
    
 # 删除多余的子图
    if len(datasets) < len(axes):
        fig.delaxes(axes[-1])
    
    plt.tight_layout()
    plt.show()
    
 # 峰度对比总结
    print(f"\n峰度对比总结:")
    print("=" * 60)
    print(f"{'分布类型':<15} {'峰度':<8} {'超额峰度':<10} {'尾部风险':<10} {'类型描述':<15}")
    print("-" * 60)
    
    for name, result in results.items():
        print(f"{name:<15} {result['kurtosis']:<8.2f} {result['excess_kurtosis']:<10.2f} " +
              f"{result['tail_risk_ratio']:<10.1f}x {result['description']:<15}")
    
 # 尾部行为对比
    print(f"\n绘制尾部行为对比图...")
    compare_tail_behavior(datasets)
    
    return analyze_kurtosis, plot_kurtosis_analysis

# 使用工具包
analyze_func, plot_func = kurtosis_analysis_toolkit()

2. 峰度检验

def kurtosis_tests():
    """峰度的统计检验方法"""
    print("峰度统计检验:")
    print("=" * 40)
    
 # 生成测试数据
    np.random.seed(42)
    
    test_datasets = {
        "正态分布": np.random.normal(0, 1, 500),
        "高峰度分布": stats.t.rvs(df=4, size=500),
        "低峰度分布": np.random.uniform(-2, 2, 500),
        "拉普拉斯分布": stats.laplace.rvs(size=500)
    }
    
    for name, data in test_datasets.items():
        print(f"\n{name}:")
        print("-" * 20)
        
 # 计算峰度
        kurt_val = stats.kurtosis(data, fisher=True)  # 超额峰度
        n = len(data)
        
        print(f"样本超额峰度: {kurt_val:.4f}")
        
 # 1. 超额峰度的大样本Z近似(不是D'Agostino变换检验)
 # 在正态总体零假设下使用偏差修正的超额峰度及其标准误。
 # 该检验只利用峰度信息,不能识别所有非正态分布。
        corrected_kurt = stats.kurtosis(data, fisher=True, bias=False)
        se_kurt = np.sqrt(24 * n * (n - 1)**2 / ((n - 3) * (n - 2) * (n + 3) * (n + 5)))
        z_kurt = corrected_kurt / se_kurt
        p_value_kurt = 2 * stats.norm.sf(abs(z_kurt))
        
        print(f"超额峰度的大样本Z近似:")
        print(f"  检验统计量 Z = {z_kurt:.4f}")
        print(f"  p值 = {p_value_kurt:.4f}")
        
        if p_value_kurt < 0.05:
            print(f"  结论: 拒绝正态峰度假设 (p < 0.05)")
        else:
            print(f"  结论: 接受正态峰度假设 (p ≥ 0.05)")
        
 # 2. Jarque-Bera检验 (偏度和峰度的联合检验)
        jb_stat, jb_pvalue = stats.jarque_bera(data)
        
        print(f"Jarque-Bera检验:")
        print(f"  JB统计量 = {jb_stat:.4f}")
        print(f"  p值 = {jb_pvalue:.4f}")
        
        if jb_pvalue < 0.05:
            print(f"  结论: 拒绝正态性假设 (p < 0.05)")
        else:
            print(f"  结论: 未拒绝正态性假设 (p ≥ 0.05),不代表已证明正态性")
        
 # 3. Anscombe-Glynn峰度检验
 # 更准确的峰度正态性检验
        def anscombe_glynn_test(data):
            # 使用SciPy的峰度检验实现,避免不完整的手写变换
            result = stats.kurtosistest(data)
            return result.statistic, result.pvalue
        
        if n > 20:  # Anscombe-Glynn检验需要足够大的样本
            ag_stat, ag_pvalue = anscombe_glynn_test(data)
            
            print(f"Anscombe-Glynn峰度检验:")
            print(f"  AG统计量 = {ag_stat:.4f}")
            print(f"  p值 = {ag_pvalue:.4f}")
            
            if ag_pvalue < 0.05:
                print(f"  结论: 拒绝正态峰度假设 (p < 0.05)")
            else:
                print(f"  结论: 接受正态峰度假设 (p ≥ 0.05)")
        
 # 4. 峰度的置信区间
 # 使用bootstrap方法
        n_bootstrap = 1000
        bootstrap_kurts = []
        
        for _ in range(n_bootstrap):
            bootstrap_sample = np.random.choice(data, size=len(data), replace=True)
            bootstrap_kurts.append(stats.kurtosis(bootstrap_sample, fisher=True))
        
        ci_lower = np.percentile(bootstrap_kurts, 2.5)
        ci_upper = np.percentile(bootstrap_kurts, 97.5)
        
        print(f"超额峰度95%置信区间: [{ci_lower:.4f}, {ci_upper:.4f}]")
        
 # 判断是否包含0(正态性)
        if ci_lower <= 0 <= ci_upper:
            print(f"  置信区间包含0,尚不能排除超额峰度为0;这不等于证明分布正态")
        else:
            print(f"  置信区间不包含0,支持非正态峰度")

kurtosis_tests()

🎯 实际应用场景

1. 金融风险管理

def financial_kurtosis_analysis():
    """金融市场的峰度分析"""
    np.random.seed(42)
    
    print("金融市场峰度风险分析:")
    print("=" * 40)
    
 # 模拟不同类型金融资产的收益率
    trading_days = 252 * 2  # 两年的交易数据
    
 # 不同资产的收益率特征
    assets = {
        "政府债券": {
            "returns": np.random.normal(0.0003, 0.005, trading_days),  # 低风险,接近正态
            "description": "低风险资产"
        },
        "大盘股票": {
            "returns": stats.t.rvs(df=6, loc=0.0005, scale=0.015, size=trading_days),  # 中等峰度
            "description": "传统股票资产"
        },
        "小盘股票": {
            "returns": stats.t.rvs(df=4, loc=0.001, scale=0.025, size=trading_days),  # 高峰度
            "description": "高风险股票"
        },
        "加密货币": {
            "returns": np.concatenate([
                np.random.normal(0.002, 0.03, int(trading_days * 0.8)),  # 正常时期
                np.random.normal(0, 0.15, int(trading_days * 0.2))       # 高波动时期
            ]),  # 极高峰度
            "description": "极高风险资产"
        }
    }
    
 # 分析每个资产
    analysis_results = {}
    
    for asset_name, asset_info in assets.items():
        returns = asset_info["returns"] * 100  # 转换为百分比
        
 # 基本统计
        mean_return = np.mean(returns)
        std_return = np.std(returns, ddof=1)
        skew_return = stats.skew(returns)
        kurt_return = stats.kurtosis(returns, fisher=False)
        excess_kurt = stats.kurtosis(returns, fisher=True)
        
 # 风险指标
        var_95 = np.percentile(returns, 5)  # 95% VaR
        var_99 = np.percentile(returns, 1)  # 99% VaR
        
 # 尾部风险分析
        tail_5pct = np.mean(returns < var_95)  # 实际5%尾部概率
        extreme_loss_3sigma = np.mean(returns < mean_return - 3 * std_return)
        normal_extreme_prob = stats.norm.cdf(-3)  # 理论正态分布的-3σ概率
        
 # 峰度的风险含义
        if excess_kurt > 3:
            risk_interpretation = "极端收益频发,黑天鹅风险高"
        elif excess_kurt > 1:
            risk_interpretation = "尾部风险显著,需要额外风险管理"
        elif excess_kurt > 0:
            risk_interpretation = "轻度尾部风险,可接受"
        else:
            risk_interpretation = "尾部风险低于正态分布"
        
        analysis_results[asset_name] = {
            'returns': returns,
            'mean': mean_return,
            'std': std_return,
            'skewness': skew_return,
            'kurtosis': kurt_return,
            'excess_kurtosis': excess_kurt,
            'var_95': var_95,
            'var_99': var_99,
            'tail_risk_ratio': extreme_loss_3sigma / normal_extreme_prob if normal_extreme_prob > 0 else 1,
            'risk_interpretation': risk_interpretation,
            'description': asset_info["description"]
        }
        
        print(f"\n{asset_name} ({asset_info['description']}):")
        print(f"  年化收益率: {mean_return * 252:.2f}%")
        print(f"  年化波动率: {std_return * np.sqrt(252):.2f}%")
        print(f"  偏度: {skew_return:.4f}")
        print(f"  峰度: {kurt_return:.4f}")
        print(f"  超额峰度: {excess_kurt:.4f}")
        print(f"  95% VaR: {var_95:.2f}%")
        print(f"  99% VaR: {var_99:.2f}%")
        print(f"  极端损失倍数: {extreme_loss_3sigma / normal_extreme_prob:.1f}x")
        print(f"  风险特征: {risk_interpretation}")
    
 # 可视化对比
    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
    
 # 收益率分布对比
    for asset_name, result in analysis_results.items():
        returns = result['returns']
        ax1.hist(returns, bins=50, alpha=0.6, density=True, 
                label=f"{asset_name} (超额峰度={result['excess_kurtosis']:.1f})")
    
    ax1.set_xlabel('日收益率 (%)')
    ax1.set_ylabel('密度')
    ax1.set_title('收益率分布对比')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    ax1.set_xlim(-10, 10)  # 限制x轴范围以便观察
    
 # 峰度 vs 尾部风险
    excess_kurts = [result['excess_kurtosis'] for result in analysis_results.values()]
    tail_risks = [result['tail_risk_ratio'] for result in analysis_results.values()]
    asset_names = list(analysis_results.keys())
    
    ax2.scatter(excess_kurts, tail_risks, s=100, alpha=0.7)
    for i, name in enumerate(asset_names):
        ax2.annotate(name, (excess_kurts[i], tail_risks[i]), 
                    xytext=(5, 5), textcoords='offset points', fontsize=9)
    
    ax2.set_xlabel('超额峰度')
    ax2.set_ylabel('极端损失风险倍数')
    ax2.set_title('峰度 vs 尾部风险关系')
    ax2.grid(True, alpha=0.3)
    
 # VaR对比
    var_95_values = [result['var_95'] for result in analysis_results.values()]
    var_99_values = [result['var_99'] for result in analysis_results.values()]
    
    x_pos = np.arange(len(asset_names))
    width = 0.35
    
    ax3.bar(x_pos - width/2, np.abs(var_95_values), width, 
           label='95% VaR', alpha=0.7, color='orange')
    ax3.bar(x_pos + width/2, np.abs(var_99_values), width, 
           label='99% VaR', alpha=0.7, color='red')
    
    ax3.set_xlabel('资产类型')
    ax3.set_ylabel('VaR (绝对值, %)')
    ax3.set_title('不同资产的VaR对比')
    ax3.set_xticks(x_pos)
    ax3.set_xticklabels(asset_names, rotation=45)
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
 # 尾部概率对比
    for asset_name, result in analysis_results.items():
        returns = result['returns']
        standardized = (returns - result['mean']) / result['std']
        
 # 计算尾部概率
        abs_returns = np.abs(standardized)
        sorted_abs = np.sort(abs_returns)
        n = len(sorted_abs)
        survival = (n - np.searchsorted(sorted_abs, sorted_abs, side='right')) / n
        
 # 只绘制尾部
        mask = survival > 1e-3
        if np.sum(mask) > 10:
            ax4.semilogy(sorted_abs[mask], survival[mask], 
                        'o-', markersize=2, alpha=0.7, label=asset_name)
    
 # 理论正态分布
    x_theory = np.linspace(0, 4, 100)
    normal_tail = 2 * (1 - stats.norm.cdf(x_theory))
    ax4.semilogy(x_theory, normal_tail, 'k--', linewidth=2, 
                alpha=0.7, label='理论正态分布')
    
    ax4.set_xlabel('|标准化收益率|')
    ax4.set_ylabel('P(|X| > x)')
    ax4.set_title('尾部概率对比')
    ax4.legend()
    ax4.grid(True, alpha=0.3)
    ax4.set_ylim(1e-3, 1)
    
    plt.tight_layout()
    plt.show()
    
 # 风险管理建议
    print(f"\n基于峰度的风险管理建议:")
    print("=" * 40)
    
    for asset_name, result in analysis_results.items():
        excess_kurt = result['excess_kurtosis']
        
        print(f"\n{asset_name}:")
        if excess_kurt > 3:
            print("  🚨 极高峰度风险:")
            print("    - 使用更保守的VaR估计")
            print("    - 考虑期权对冲策略")
            print("    - 降低仓位集中度")
            print("    - 实施动态风险管理")
        elif excess_kurt > 1:
            print("  ⚠️  高峰度风险:")
            print("    - 调整风险模型参数")
            print("    - 增加压力测试频率")
            print("    - 考虑尾部风险对冲")
        elif excess_kurt > 0:
            print("  ✅ 中等峰度风险:")
            print("    - 维持标准风险管理")
            print("    - 定期监控峰度变化")
        else:
            print("  📈 低峰度资产:")
            print("    - 低峰度不足以支持正态假设,需结合分布诊断与尾部评估")
            print("    - 是否适合作为组合稳定器,需结合波动、相关性、流动性及损失风险评估,不能仅凭低峰度判断")
    
 # 组合构建建议
    print(f"\n投资组合构建建议:")
    print("-" * 25)
    
 # 按峰度排序
    sorted_assets = sorted(analysis_results.items(), 
                          key=lambda x: x[1]['excess_kurtosis'])
    
    print("峰度从低到高排序:")
    for asset_name, result in sorted_assets:
        excess_kurt = result['excess_kurtosis']
        print(f"  {asset_name}: 超额峰度 = {excess_kurt:.2f}")
    
    print(f"\n建议配置策略:")
    print("  模拟配置假设:将低峰度资产(本例标签为政府债券、大盘股)作为保守型候选;峰度本身不能支持实际配置比例或风险等级")
    print("  平衡型: 混合配置,控制组合整体峰度")
    print("  激进型: 可接受高峰度,但需要严格风险控制")

financial_kurtosis_analysis()

2. 质量控制应用

def manufacturing_kurtosis_analysis():
    """制造业中的峰度质量分析"""
    np.random.seed(42)
    
    print("制造业峰度质量分析:")
    print("=" * 40)
    
 # 模拟不同生产过程的质量数据
    n_samples = 1000
    
    production_processes = {
        "标准工艺": {
            "data": np.random.normal(100, 1.5, n_samples),  # 标准正态过程
            "description": "稳定的标准化生产工艺"
        },
        "自动化生产": {
            "data": np.random.uniform(98.5, 101.5, n_samples),  # 低峰度,均匀分布
            "description": "高度自动化,变异均匀"
        },
        "手工调整": {
            "data": np.concatenate([
                np.random.normal(100, 0.8, int(n_samples * 0.8)),   # 大部分精确
                np.random.normal(100, 3, int(n_samples * 0.2))      # 少数偏差大
            ]),  # 高峰度,混合分布
            "description": "人工调整,大多精确但偶有偏差"
        },
        "设备老化": {
            "data": stats.t.rvs(df=3, loc=100, scale=2, size=n_samples),  # 高峰度t分布
            "description": "设备磨损,性能不稳定"
        }
    }
    
 # 质量规格
    target = 100
    usl = 105  # 上规格限
    lsl = 95   # 下规格限
    
    print(f"质量规格: 目标值 = {target}, 规格范围 = [{lsl}, {usl}]")
    
 # 分析每个生产过程
    process_results = {}
    
    for process_name, process_info in production_processes.items():
        data = process_info["data"]
        
 # 基本统计
        mean_val = np.mean(data)
        std_val = np.std(data, ddof=1)
        skew_val = stats.skew(data)
        kurt_val = stats.kurtosis(data, fisher=False)
        excess_kurt = stats.kurtosis(data, fisher=True)
        
 # 过程能力分析
        cp = (usl - lsl) / (6 * std_val)  # 过程能力
        cpk = min((usl - mean_val) / (3 * std_val), 
                  (mean_val - lsl) / (3 * std_val))  # 过程能力指数
        
 # 合格率
        conforming = np.sum((data >= lsl) & (data <= usl))
        conformance_rate = conforming / len(data)
        
 # 基于峰度的质量风险评估
 # 计算超出±3σ的实际概率
        extreme_count = np.sum(np.abs(data - mean_val) > 3 * std_val)
        actual_extreme_rate = extreme_count / len(data)
        theoretical_extreme_rate = 2 * (1 - stats.norm.cdf(3))  # 理论正态概率
        
 # 峰度对质量的影响分析
        if excess_kurt > 2:
            quality_impact = "高峰度:极值频发,需要严格监控"
            risk_level = "高"
        elif excess_kurt > 0.5:
            quality_impact = "中等峰度:存在异常值风险"
            risk_level = "中"
        elif excess_kurt > -0.5:
            quality_impact = "峰度接近正态参考值:过程稳定性仍需时序监控判断"
            risk_level = "低"
        else:
            quality_impact = "低峰度:不能据此判断精度,需结合偏差、变异与规格限评估"
            risk_level = "中"
        
        process_results[process_name] = {
            'data': data,
            'mean': mean_val,
            'std': std_val,
            'skewness': skew_val,
            'kurtosis': kurt_val,
            'excess_kurtosis': excess_kurt,
            'cp': cp,
            'cpk': cpk,
            'conformance_rate': conformance_rate,
            'actual_extreme_rate': actual_extreme_rate,
            'extreme_risk_ratio': actual_extreme_rate / theoretical_extreme_rate if theoretical_extreme_rate > 0 else 1,
            'quality_impact': quality_impact,
            'risk_level': risk_level,
            'description': process_info["description"]
        }
        
        print(f"\n{process_name} ({process_info['description']}):")
        print(f"  均值: {mean_val:.2f}")
        print(f"  标准差: {std_val:.2f}")
        print(f"  峰度: {kurt_val:.3f}")
        print(f"  超额峰度: {excess_kurt:.3f}")
        print(f"  Cp: {cp:.3f}")
        print(f"  Cpk: {cpk:.3f}")
        print(f"  合格率: {conformance_rate:.1%}")
        print(f"  极值率: {actual_extreme_rate:.1%} (理论: {theoretical_extreme_rate:.1%})")
        print(f"  极值风险倍数: {actual_extreme_rate / theoretical_extreme_rate:.1f}x")
        print(f"  质量影响: {quality_impact}")
        print(f"  风险等级: {risk_level}")
    
 # 可视化质量分析
    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
    
 # 质量分布对比
    colors = plt.cm.Set2(np.linspace(0, 1, len(process_results)))
    
    for i, (process_name, result) in enumerate(process_results.items()):
        data = result['data']
        
        ax1.hist(data, bins=40, alpha=0.6, density=True, 
                color=colors[i], label=f"{process_name} (超额峰度={result['excess_kurtosis']:.1f})")
    
 # 添加规格限
    ax1.axvline(lsl, color='red', linestyle='--', linewidth=2, label='规格限')
    ax1.axvline(usl, color='red', linestyle='--', linewidth=2)
    ax1.axvline(target, color='green', linestyle='-', linewidth=2, label='目标值')
    
    ax1.set_xlabel('测量值')
    ax1.set_ylabel('密度')
    ax1.set_title('生产过程质量分布对比')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
 # 峰度 vs 过程能力
    excess_kurts = [result['excess_kurtosis'] for result in process_results.values()]
    cpk_values = [result['cpk'] for result in process_results.values()]
    process_names = list(process_results.keys())
    
    ax2.scatter(excess_kurts, cpk_values, s=100, alpha=0.7, c=colors)
    for i, name in enumerate(process_names):
        ax2.annotate(name, (excess_kurts[i], cpk_values[i]), 
                    xytext=(5, 5), textcoords='offset points', fontsize=9)
    
    ax2.axhline(y=1.33, color='green', linestyle='--', alpha=0.7, label='优秀水平')
    ax2.axhline(y=1.0, color='orange', linestyle='--', alpha=0.7, label='可接受水平')
    ax2.set_xlabel('超额峰度')
    ax2.set_ylabel('过程能力指数 (Cpk)')
    ax2.set_title('峰度 vs 过程能力关系')
    ax2.legend()
    ax2.grid(True, alpha=0.3)
    
 # 极值风险对比
    extreme_risks = [result['extreme_risk_ratio'] for result in process_results.values()]
    
    ax3.bar(process_names, extreme_risks, alpha=0.7, color=colors)
    ax3.axhline(y=1, color='red', linestyle='--', alpha=0.7, label='理论正态水平')
    ax3.set_ylabel('极值风险倍数')
    ax3.set_title('各过程极值风险对比')
    ax3.tick_params(axis='x', rotation=45)
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
 # 在柱子上显示数值
    for i, risk in enumerate(extreme_risks):
        ax3.text(i, risk + 0.1, f'{risk:.1f}x', ha='center', va='bottom')
    
 # 合格率 vs 峰度
    conformance_rates = [result['conformance_rate'] * 100 for result in process_results.values()]
    
    ax4.scatter(excess_kurts, conformance_rates, s=100, alpha=0.7, c=colors)
    for i, name in enumerate(process_names):
        ax4.annotate(name, (excess_kurts[i], conformance_rates[i]), 
                    xytext=(5, 5), textcoords='offset points', fontsize=9)
    
    ax4.set_xlabel('超额峰度')
    ax4.set_ylabel('合格率 (%)')
    ax4.set_title('峰度 vs 合格率关系')
    ax4.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()
    
 # 改进建议
    print(f"\n基于峰度的过程改进建议:")
    print("=" * 40)
    
    for process_name, result in process_results.items():
        excess_kurt = result['excess_kurtosis']
        cpk = result['cpk']
        
        print(f"\n{process_name}:")
        
        if excess_kurt > 2 and cpk < 1.33:
            print("  🚨 高峰度低能力:")
            print("    - 立即调查极值产生原因")
            print("    - 实施更严格的过程控制")
            print("    - 考虑更换设备或工艺")
            print("    - 增加实时监控频率")
        elif excess_kurt > 1:
            print("  ⚠️  中高峰度:")
            print("    - 分析异常值产生机制")
            print("    - 优化操作标准化程度")
            print("    - 加强操作员培训")
        elif excess_kurt < -1:
            print("  📊 低峰度分析:")
            print("    - 检查测量系统精度")
            print("    - 评估过程变异来源")
            print("    - 考虑提高过程精度")
        else:
            print("  ✅ 峰度正常:")
            print("    - 维持当前过程控制")
            print("    - 继续监控峰度趋势")
        
 # 基于Cpk的补充建议
        if cpk < 1.0:
            print("    - Cpk偏低,需要提高过程能力")
        elif cpk > 1.33:
            print("    - Cpk优秀,过程能力充足")
    
 # 监控策略建议
    print(f"\n峰度监控策略:")
    print("-" * 20)
    print("1. 建立峰度控制图,设定±2σ控制限")
    print("2. 当超额峰度 > 1.5时触发调查")
    print("3. 结合Cpk和峰度进行过程评估")
    print("4. 定期进行峰度趋势分析")
    print("5. 针对高峰度过程制定专项改进计划")

manufacturing_kurtosis_analysis()

🛠️ 实用技巧

1. 峰度异常检测系统

def kurtosis_anomaly_detection():
    """基于峰度的异常检测系统"""
    
    class KurtosisAnomalyDetector:
        def __init__(self, window_size=100, threshold=1.5):
            self.window_size = window_size
            self.threshold = threshold
            self.data_buffer = []
            self.kurtosis_history = []
            self.anomalies = []
            self.baseline_kurtosis = None
        
        def add_data(self, new_data):
            """添加新数据并检测异常"""
            if isinstance(new_data, (list, np.ndarray)):
                self.data_buffer.extend(new_data)
            else:
                self.data_buffer.append(new_data)
            
 # 保持缓冲区大小
            if len(self.data_buffer) > self.window_size * 2:
                self.data_buffer = self.data_buffer[-self.window_size:]
            
 # 计算当前峰度
            if len(self.data_buffer) >= self.window_size:
                current_data = self.data_buffer[-self.window_size:]
                current_kurtosis = stats.kurtosis(current_data, fisher=True)
                self.kurtosis_history.append(current_kurtosis)
                
 # 设定基线(前10个窗口的平均峰度)
                if self.baseline_kurtosis is None and len(self.kurtosis_history) >= 10:
                    self.baseline_kurtosis = np.mean(self.kurtosis_history[:10])
                
 # 检测异常
                if self.baseline_kurtosis is not None:
                    self._detect_anomaly(current_kurtosis)
                
                return current_kurtosis
            return None
        
        def _detect_anomaly(self, current_kurtosis):
            """检测峰度异常"""
            deviation = abs(current_kurtosis - self.baseline_kurtosis)
            
            if deviation > self.threshold:
                anomaly_type = self._classify_anomaly(current_kurtosis)
                
                self.anomalies.append({
                    'timestamp': len(self.kurtosis_history),
                    'kurtosis': current_kurtosis,
                    'baseline': self.baseline_kurtosis,
                    'deviation': deviation,
                    'type': anomaly_type,
                    'severity': self._get_severity(deviation)
                })
        
        def _classify_anomaly(self, kurtosis):
            """分类异常类型"""
            if kurtosis > self.baseline_kurtosis + self.threshold:
                return "峰度激增"
            else:
                return "峰度降低"
        
        def _get_severity(self, deviation):
            """获取异常严重程度"""
            if deviation > 3 * self.threshold:
                return "严重"
            elif deviation > 2 * self.threshold:
                return "中等"
            else:
                return "轻微"
        
        def get_current_status(self):
            """获取当前状态"""
            if not self.kurtosis_history:
                return "无数据"
            
            if self.baseline_kurtosis is None:
                return "基线未建立,尚未进行异常判定"
            
            if not self.anomalies:
                return "正常"
            
            latest_anomaly = self.anomalies[-1]
            if latest_anomaly['timestamp'] == len(self.kurtosis_history):
                return f"异常: {latest_anomaly['type']} ({latest_anomaly['severity']})"
            else:
                return "已恢复"
        
        def plot_monitoring(self):
            """绘制监控图表"""
            if len(self.kurtosis_history) < 2:
                print("数据不足,无法绘图")
                return
            
            fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(12, 12))
            
 # 峰度时间序列
            timestamps = range(len(self.kurtosis_history))
            ax1.plot(timestamps, self.kurtosis_history, 'b-', linewidth=2, label='峰度')
            
            if self.baseline_kurtosis is not None:
                ax1.axhline(y=self.baseline_kurtosis, color='green', linestyle='-', 
                           alpha=0.7, label=f'基线 = {self.baseline_kurtosis:.3f}')
                ax1.axhline(y=self.baseline_kurtosis + self.threshold, color='orange', 
                           linestyle='--', alpha=0.7, label=f'警戒线 ±{self.threshold}')
                ax1.axhline(y=self.baseline_kurtosis - self.threshold, color='orange', 
                           linestyle='--', alpha=0.7)
            
 # 标记异常点
            for anomaly in self.anomalies:
                color = {'轻微': 'yellow', '中等': 'orange', '严重': 'red'}[anomaly['severity']]
                ax1.scatter(anomaly['timestamp'] - 1, anomaly['kurtosis'], 
                          color=color, s=100, marker='X', alpha=0.8,
                          label=f"{anomaly['type']} ({anomaly['severity']})")
            
            ax1.set_title('峰度监控时间序列')
            ax1.set_xlabel('时间窗口')
            ax1.set_ylabel('超额峰度')
            ax1.legend()
            ax1.grid(True, alpha=0.3)
            
 # 异常偏差程度
            if self.anomalies:
                anomaly_times = [a['timestamp'] - 1 for a in self.anomalies]
                deviations = [a['deviation'] for a in self.anomalies]
                colors = [{'轻微': 'yellow', '中等': 'orange', '严重': 'red'}[a['severity']] 
                         for a in self.anomalies]
                
                ax2.bar(anomaly_times, deviations, color=colors, alpha=0.7)
                ax2.axhline(y=self.threshold, color='red', linestyle='--', 
                           alpha=0.7, label=f'阈值 = {self.threshold}')
                ax2.set_title('异常偏差程度')
                ax2.set_xlabel('时间窗口')
                ax2.set_ylabel('偏差幅度')
                ax2.legend()
                ax2.grid(True, alpha=0.3)
            
 # 当前数据分布
            if len(self.data_buffer) >= self.window_size:
                current_data = self.data_buffer[-self.window_size:]
                ax3.hist(current_data, bins=30, density=True, alpha=0.7, 
                        color='skyblue', edgecolor='black')
                
                current_kurtosis = stats.kurtosis(current_data, fisher=True)
                ax3.text(0.02, 0.98, f'当前超额峰度: {current_kurtosis:.3f}', 
                        transform=ax3.transAxes, verticalalignment='top',
                        bbox=dict(boxstyle="round,pad=0.3", facecolor="white", alpha=0.8))
                
                ax3.set_title(f'当前数据分布 (最近{self.window_size}个点)')
                ax3.set_xlabel('数值')
                ax3.set_ylabel('密度')
                ax3.grid(True, alpha=0.3)
            
            plt.tight_layout()
            plt.show()
        
        def generate_report(self):
            """生成监控报告"""
            print("峰度异常检测报告")
            print("=" * 30)
            
            print(f"监控窗口大小: {self.window_size}")
            print(f"异常阈值: {self.threshold}")
            print(f"基线峰度: {self.baseline_kurtosis:.4f}" if self.baseline_kurtosis is not None else "基线未建立")
            print(f"当前状态: {self.get_current_status()}")
            print(f"监控周期数: {len(self.kurtosis_history)}")
            print(f"检测到异常: {len(self.anomalies)}次")
            
            if self.anomalies:
                print(f"\n异常详情:")
                for i, anomaly in enumerate(self.anomalies[-5:], 1):  # 显示最近5次异常
                    print(f"  {i}. 时间窗口{anomaly['timestamp']}: {anomaly['type']}")
                    print(f"     峰度: {anomaly['kurtosis']:.4f} (偏差: {anomaly['deviation']:.4f})")
                    print(f"     严重程度: {anomaly['severity']}")
    
 # 演示异常检测系统
    print("峰度异常检测系统演示:")
    print("=" * 40)
    
 # 创建检测器
    detector = KurtosisAnomalyDetector(window_size=50, threshold=1.0)
    
    np.random.seed(42)
    
 # 阶段1: 正常数据(基线建立)
    print("阶段1: 建立基线...")
    normal_data = np.random.normal(0, 1, 500)
    for data_point in normal_data:
        detector.add_data(data_point)
    print(f"基线峰度: {detector.baseline_kurtosis:.4f}")
    
 # 阶段2: 峰度异常(高峰度)
    print("\n阶段2: 注入高峰度数据...")
    high_kurt_data = stats.t.rvs(df=3, size=100)
    for data_point in high_kurt_data:
        detector.add_data(data_point)
    print(f"当前状态: {detector.get_current_status()}")
    
 # 阶段3: 峰度异常(低峰度)
    print("\n阶段3: 注入低峰度数据...")
    low_kurt_data = np.random.uniform(-2, 2, 100)
    for data_point in low_kurt_data:
        detector.add_data(data_point)
    print(f"当前状态: {detector.get_current_status()}")
    
 # 阶段4: 恢复正常
    print("\n阶段4: 恢复正常数据...")
    recovery_data = np.random.normal(0, 1, 100)
    for data_point in recovery_data:
        detector.add_data(data_point)
    print(f"当前状态: {detector.get_current_status()}")
    
 # 生成报告和图表
    detector.generate_report()
    detector.plot_monitoring()

kurtosis_anomaly_detection()

🔗 相关知识

#统计学 #峰度 #描述性统计 #分布形状 #尖峭程度 #基础