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

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

warning 适用边界与维护说明

本文适合学习偏度计算、统计检验、模拟业务分析、变换比较与滚动监控,不宜直接作为生产工具包复用。客户细分仍直接组合分别截尾的订单金额与购买频次数组,可能因长度不一致产生广播错误,即使长度相同也不能保证同一客户对应,订单级金额与客户级频次亦未统一粒度;金融VaR数值已采用损失口径,但图中仍将该数值直接标在收益率横轴上,不能将该竖线理解为收益率左尾阈值。零偏度或低偏度不能证明对称、均匀或正态,检验不显著及Bootstrap区间包含零也不能证明对称性;固定分位数截尾不是异常值识别,其后偏度仅描述保留样本。金融、业务、质量建议及监控阈值仅为模拟讨论规则,不能仅凭偏度推断客户占比、满意度、投资尾部风险或过程稳定性,Cp/Cpk解释还需结合稳定过程、变异估计口径和适当的分布条件。本次仅作全文结构审阅,未运行代码或开展外部事实核验。

📐 偏度(Skewness)

abstract 📋 本节概览

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

🤔 什么是偏度?

note 📖 **偏度的定义**

偏度是衡量数据分布不对称程度的统计量,描述分布相对于对称分布(如正态分布)的偏斜方向和程度。

数学表达式: $$\text{Skewness} = \frac{E[(X-\mu)^3]}{\sigma^3} = \frac{\mu_3}{\sigma^3}$$

其中:

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

偏度值的含义:

  • 偏度 = 0:三阶中心矩为零,但不必然说明分布对称;对称分布在三阶绝对矩有限且标准差非零时偏度为零(如非退化正态分布)
  • 偏度 > 0:右偏(正偏),尾部向右延伸
  • 偏度 < 0:左偏(负偏),尾部向左延伸

生活例子:

  • 收入分布:通常右偏,少数高收入者拉长右尾
  • 考试成绩:可能左偏,大多数学生分数较高
  • 房价分布:通常右偏,豪宅拉高平均价格
  • 年龄分布:在某些群体中可能呈现不同偏斜

📊 偏度的类型与特征

1. 三种偏度类型

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

def plot_skewness_types():
    """展示不同类型的偏度"""
    fig, ((ax1, ax2, ax3), (ax4, ax5, ax6)) = plt.subplots(2, 3, figsize=(15, 10))
    
 # 1. 对称分布(偏度≈0)
    np.random.seed(42)
    symmetric_data = np.random.normal(0, 1, 1000)
    skew_sym = stats.skew(symmetric_data)
    
    ax1.hist(symmetric_data, bins=30, density=True, alpha=0.7, color='blue', edgecolor='black')
    ax1.set_title(f'对称分布\n偏度 = {skew_sym:.3f}')
    ax1.set_ylabel('密度')
    ax1.grid(True, alpha=0.3)
    
 # 标注均值、中位数、众数
    mean_sym = np.mean(symmetric_data)
    median_sym = np.median(symmetric_data)
    ax1.axvline(mean_sym, color='red', linestyle='-', linewidth=2, label=f'均值={mean_sym:.2f}')
    ax1.axvline(median_sym, color='green', linestyle='--', linewidth=2, label=f'中位数={median_sym:.2f}')
    ax1.legend()
    
 # 2. 右偏分布(正偏度)
    right_skewed_data = np.random.lognormal(0, 0.8, 1000)
    skew_right = stats.skew(right_skewed_data)
    
    ax2.hist(right_skewed_data, bins=30, density=True, alpha=0.7, color='orange', edgecolor='black')
    ax2.set_title(f'右偏分布(正偏)\n偏度 = {skew_right:.3f}')
    ax2.grid(True, alpha=0.3)
    
    mean_right = np.mean(right_skewed_data)
    median_right = np.median(right_skewed_data)
    ax2.axvline(mean_right, color='red', linestyle='-', linewidth=2, label=f'均值={mean_right:.2f}')
    ax2.axvline(median_right, color='green', linestyle='--', linewidth=2, label=f'中位数={median_right:.2f}')
    ax2.legend()
    
 # 3. 左偏分布(负偏度)
    left_skewed_data = 10 - np.random.lognormal(0, 0.6, 1000)
    skew_left = stats.skew(left_skewed_data)
    
    ax3.hist(left_skewed_data, bins=30, density=True, alpha=0.7, color='green', edgecolor='black')
    ax3.set_title(f'左偏分布(负偏)\n偏度 = {skew_left:.3f}')
    ax3.grid(True, alpha=0.3)
    
    mean_left = np.mean(left_skewed_data)
    median_left = np.median(left_skewed_data)
    ax3.axvline(mean_left, color='red', linestyle='-', linewidth=2, label=f'均值={mean_left:.2f}')
    ax3.axvline(median_left, color='green', linestyle='--', linewidth=2, label=f'中位数={median_left:.2f}')
    ax3.legend()
    
 # 4-6. 箱线图对比
    data_sets = [symmetric_data, right_skewed_data, left_skewed_data]
    labels = ['对称分布', '右偏分布', '左偏分布']
    colors = ['blue', 'orange', 'green']
    
    for i, (data, label, color) in enumerate(zip(data_sets, labels, colors)):
        ax = [ax4, ax5, ax6][i]
        bp = ax.boxplot(data, patch_artist=True, labels=[label])
        bp['boxes'][0].set_facecolor(color)
        bp['boxes'][0].set_alpha(0.7)
        
 # 标注关键统计量
        q1, median, q3 = np.percentile(data, [25, 50, 75])
        mean_val = np.mean(data)
        
        ax.scatter([1], [mean_val], color='red', s=100, marker='D', label='均值')
        ax.set_title(f'{label}\n偏度 = {stats.skew(data):.3f}')
        ax.grid(True, alpha=0.3)
        if i == 0:
            ax.legend()
    
    plt.tight_layout()
    plt.show()
    
 # 数值比较
    print("偏度类型对比:")
    print("=" * 50)
    
    datasets = [
        ("对称分布", symmetric_data),
        ("右偏分布", right_skewed_data), 
        ("左偏分布", left_skewed_data)
    ]
    
    for name, data in datasets:
        mean_val = np.mean(data)
        median_val = np.median(data)
        skew_val = stats.skew(data)
        
        print(f"\n{name}:")
        print(f"  均值: {mean_val:.3f}")
        print(f"  中位数: {median_val:.3f}")
        print(f"  偏度: {skew_val:.3f}")
        print(f"  均值-中位数: {mean_val - median_val:.3f}")
        
        if abs(skew_val) < 0.5:
            skew_desc = "近似对称"
        elif skew_val > 0:
            if skew_val < 1:
                skew_desc = "轻度右偏"
            elif skew_val < 2:
                skew_desc = "中度右偏"
            else:
                skew_desc = "高度右偏"
        else:
            if skew_val > -1:
                skew_desc = "轻度左偏"
            elif skew_val > -2:
                skew_desc = "中度左偏"
            else:
                skew_desc = "高度左偏"
        
        print(f"  偏度程度: {skew_desc}")

plot_skewness_types()

2. 偏度的计算方法

def calculate_skewness_methods():
    """演示偏度的不同计算方法"""
    np.random.seed(42)
    
 # 生成右偏数据
    data = np.random.lognormal(1, 0.5, 1000)
    
    print("偏度的计算方法:")
    print("=" * 40)
    
 # 1. 手动计算 - 第三中心矩方法
    n = len(data)
    mean = np.mean(data)
    std = np.std(data, ddof=0)  # 与三阶样本中心矩使用相同的n分母,对应stats.skew默认的未校正矩偏度
    
 # 第三中心矩
    third_moment = np.mean((data - mean)**3)
    skew_manual = third_moment / (std**3)
    
    print(f"1. 手动计算(第三中心矩法):")
    print(f"   均值: {mean:.4f}")
    print(f"   标准差: {std:.4f}")
    print(f"   第三中心矩: {third_moment:.4f}")
    print(f"   偏度: {skew_manual:.4f}")
    
 # 2. Pearson第一偏度系数
    median = np.median(data)
    from scipy.stats import gaussian_kde
    kde_first = gaussian_kde(data)
    mode_grid = np.linspace(data.min(), data.max(), 1000)
    mode_first = mode_grid[np.argmax(kde_first(mode_grid))]
    pearson_skew1 = (mean - mode_first) / std
    
    print(f"\n2. Pearson第一偏度系数:")
    print(f"   公式: (均值 - 众数) / 标准差;本例众数由核密度峰值近似")
    print(f"   偏度: {pearson_skew1:.4f}")
    
 # 3. Pearson第二偏度系数
 # 使用均值、中位数和标准差,不需要估计众数;下方核密度计算不参与第二系数
    from scipy.stats import gaussian_kde
    kde = gaussian_kde(data)
    x_range = np.linspace(data.min(), data.max(), 1000)
    kde_values = kde(x_range)
    mode_approx = x_range[np.argmax(kde_values)]
    
    pearson_skew2 = 3 * (mean - median) / std
    
    print(f"\n3. Pearson第二偏度系数:")
    print(f"   公式: 3 × (均值 - 中位数) / 标准差")
    print(f"   偏度: {pearson_skew2:.4f}")
    
 # 4. scipy.stats 计算
    scipy_skew = stats.skew(data)
    
    print(f"\n4. SciPy统计函数:")
    print(f"   偏度: {scipy_skew:.4f}")
    
 # 5. 未校正与偏差校正的样本偏度
    unadjusted_skew = stats.skew(data, bias=True)
    adjusted_skew = stats.skew(data, bias=False)
    
    print(f"\n5. 样本偏度口径对比:")
    print(f"   未校正矩偏度: {unadjusted_skew:.4f}")
    print(f"   偏差校正样本偏度: {adjusted_skew:.4f}")
    
 # 6. 偏度的置信区间
 # 使用bootstrap方法
    n_bootstrap = 1000
    bootstrap_skews = []
    
    for _ in range(n_bootstrap):
        bootstrap_sample = np.random.choice(data, size=len(data), replace=True)
        bootstrap_skews.append(stats.skew(bootstrap_sample))
    
    skew_ci_lower = np.percentile(bootstrap_skews, 2.5)
    skew_ci_upper = np.percentile(bootstrap_skews, 97.5)
    
    print(f"\n6. 偏度的95%置信区间 (Bootstrap):")
    print(f"   [{skew_ci_lower:.4f}, {skew_ci_upper:.4f}]")
    
 # 7. 样本量对偏度估计的影响
    print(f"\n7. 样本量对偏度估计的影响:")
    sample_sizes = [50, 100, 500, 1000, 5000]
    true_data = np.random.lognormal(1, 0.5, 10000)  # 真实总体
    true_skew = stats.skew(true_data)
    
    print(f"   真实偏度: {true_skew:.4f}")
    print("   样本量 -> 估计偏度 (标准误差)")
    
    for size in sample_sizes:
        sample_skews = []
        for _ in range(100):  # 100次重复采样
            sample = np.random.choice(true_data, size=size, replace=False)
            sample_skews.append(stats.skew(sample))
        
        mean_skew = np.mean(sample_skews)
        std_skew = np.std(sample_skews, ddof=1)
        
        print(f"   {size:4d} -> {mean_skew:.4f} ({std_skew:.4f})")

calculate_skewness_methods()

💻 Python实现

1. 基本计算与可视化

def skewness_analysis_toolkit():
    """偏度分析的完整工具包"""
    
    def analyze_skewness(data, name="数据"):
        """分析数据的偏度"""
 # 基本统计量
        mean_val = np.mean(data)
        median_val = np.median(data)
        std_val = np.std(data, ddof=1)
        skew_val = stats.skew(data)
        
 # 偏度解释
        if abs(skew_val) < 0.5:
            skew_desc = "近似对称"
            color = 'blue'
        elif skew_val > 0:
            if skew_val < 1:
                skew_desc = "轻度右偏"
                color = 'orange'
            elif skew_val < 2:
                skew_desc = "中度右偏"
                color = 'red'
            else:
                skew_desc = "高度右偏"
                color = 'darkred'
        else:
            if skew_val > -1:
                skew_desc = "轻度左偏"
                color = 'lightgreen'
            elif skew_val > -2:
                skew_desc = "中度左偏"
                color = 'green'
            else:
                skew_desc = "高度左偏"
                color = 'darkgreen'
        
        print(f"{name}偏度分析:")
        print("-" * 30)
        print(f"样本量: {len(data)}")
        print(f"均值: {mean_val:.4f}")
        print(f"中位数: {median_val:.4f}")
        print(f"标准差: {std_val:.4f}")
        print(f"偏度: {skew_val:.4f}")
        print(f"偏度程度: {skew_desc}")
        print(f"均值-中位数: {mean_val - median_val:.4f}")
        
        return {
            'mean': mean_val,
            'median': median_val,
            'std': std_val,
            'skewness': skew_val,
            'description': skew_desc,
            'color': color
        }
    
    def plot_skewness_analysis(data, name="数据", ax=None):
        """绘制偏度分析图"""
        if ax is None:
            fig, ax = plt.subplots(1, 1, figsize=(10, 6))
        
 # 分析偏度
        result = analyze_skewness(data, name)
        
 # 绘制直方图
        ax.hist(data, bins=30, density=True, alpha=0.7, 
               color=result['color'], edgecolor='black')
        
 # 添加统计线
        ax.axvline(result['mean'], color='red', linestyle='-', 
                  linewidth=2, label=f"均值 = {result['mean']:.2f}")
        ax.axvline(result['median'], color='blue', linestyle='--', 
                  linewidth=2, label=f"中位数 = {result['median']:.2f}")
        
 # 尝试拟合正态分布作为对比
        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, 'g--', linewidth=2, alpha=0.7, 
               label="正态分布拟合")
        
        ax.set_title(f'{name} - {result["description"]}\n偏度 = {result["skewness"]:.3f}')
        ax.set_xlabel('值')
        ax.set_ylabel('密度')
        ax.legend()
        ax.grid(True, alpha=0.3)
        
        return result
    
 # 示例应用:分析不同类型的数据
    print("偏度分析工具包演示:")
    print("=" * 50)
    
 # 生成不同偏度的示例数据
    np.random.seed(42)
    
    datasets = {
        "正态分布": np.random.normal(50, 10, 1000),
        "收入分布": np.random.lognormal(3.5, 0.8, 1000),
        "考试成绩": 100 - np.random.exponential(15, 1000),
        "年龄分布": np.random.gamma(2, 15, 1000) + 18
    }
    
 # 分析每个数据集
    fig, axes = plt.subplots(2, 2, figsize=(15, 12))
    axes = axes.flatten()
    
    results = {}
    for i, (name, data) in enumerate(datasets.items()):
 # 演示固定分位数截尾,不等同于异常值识别;后续偏度仅描述截尾样本
        data = data[(data > np.percentile(data, 1)) & (data < np.percentile(data, 99))]
        
        print(f"\n{i+1}. {name}:")
        result = plot_skewness_analysis(data, name, axes[i])
        results[name] = result
    
    plt.tight_layout()
    plt.show()
    
 # 偏度对比总结
    print(f"\n偏度对比总结:")
    print("=" * 50)
    print(f"{'数据类型':<10} {'偏度':<8} {'程度':<10} {'均值-中位数':<12}")
    print("-" * 50)
    
    for name, result in results.items():
        diff = result['mean'] - result['median']
        print(f"{name:<10} {result['skewness']:<8.3f} {result['description']:<10} {diff:<12.3f}")
    
    return analyze_skewness, plot_skewness_analysis

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

2. 偏度检验

def skewness_tests():
    """偏度的统计检验方法"""
    print("偏度统计检验:")
    print("=" * 40)
    
 # 生成测试数据
    np.random.seed(42)
    
 # 不同偏度的数据
    test_datasets = {
        "正态分布": np.random.normal(0, 1, 500),
        "右偏分布": np.random.exponential(1, 500),
        "左偏分布": -np.random.exponential(1, 500),
        "轻度右偏": np.random.gamma(3, 1, 500)
    }
    
    for name, data in test_datasets.items():
        print(f"\n{name}:")
        print("-" * 20)
        
 # 计算偏度
        skew_val = stats.skew(data)
        n = len(data)
        
        print(f"样本偏度: {skew_val:.4f}")
        
 # 1. D'Agostino偏度检验
 # 使用正态总体参照检验偏度是否偏离零,不是任意分布的通用对称性检验
 # stats.skewtest要求至少8个观测;本例各组有500个观测
        z_skew, p_value_skew = stats.skewtest(data)
        
        print(f"D'Agostino偏度检验(正态参照):")
        print(f"  检验统计量 Z = {z_skew:.4f}")
        print(f"  p值 = {p_value_skew:.4f}")
        
        if p_value_skew < 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. 偏度的置信区间
 # 使用bootstrap方法
        n_bootstrap = 1000
        bootstrap_skews = []
        
        for _ in range(n_bootstrap):
            bootstrap_sample = np.random.choice(data, size=len(data), replace=True)
            bootstrap_skews.append(stats.skew(bootstrap_sample))
        
        ci_lower = np.percentile(bootstrap_skews, 2.5)
        ci_upper = np.percentile(bootstrap_skews, 97.5)
        
        print(f"偏度95%置信区间: [{ci_lower:.4f}, {ci_upper:.4f}]")
        
 # 判断偏度区间是否包含0;包含0不能证明对称性
        if ci_lower <= 0 <= ci_upper:
            print(f"  置信区间包含0,当前区间估计未排除零偏度;不能据此证明分布对称")
        else:
            print(f"  置信区间不包含0,支持非对称性")

skewness_tests()

🎯 实际应用场景

1. 金融数据分析

def financial_skewness_analysis():
    """金融数据的偏度分析"""
    np.random.seed(42)
    
    print("金融数据偏度分析:")
    print("=" * 40)
    
 # 模拟不同类型股票的收益率数据
    trading_days = 252  # 一年的交易日
    
 # 不同风险特征的股票
    stocks = {
        "蓝筹股": np.random.normal(0.0008, 0.02, trading_days),  # 低风险,接近对称
        "成长股": np.random.lognormal(-0.001, 0.03, trading_days) - 1,  # 轻度右偏
        "小盘股": np.concatenate([
            np.random.normal(0.001, 0.025, int(trading_days*0.8)),  # 大部分正常交易
            np.random.normal(-0.05, 0.01, trading_days - int(trading_days*0.8))   # 偶尔大跌
        ]),  # 左偏
        "科技股": np.concatenate([
            np.random.normal(0.002, 0.03, int(trading_days*0.9)),
            np.random.normal(0.08, 0.02, trading_days - int(trading_days*0.9))   # 偶尔暴涨
        ])  # 右偏
    }
    
 # 分析每只股票
    analysis_results = {}
    
    for stock_name, returns in stocks.items():
 # 转换为百分比
        returns_pct = returns * 100
        
 # 基本统计
        mean_return = np.mean(returns_pct)
        std_return = np.std(returns_pct, ddof=1)
        skew_return = stats.skew(returns_pct)
        
 # 风险指标
        var_95 = np.percentile(-returns_pct, 95)  # 损失=-收益率,采用95%损失分位数作为VaR;单位为百分比
        
 # 偏度的风险含义
        if skew_return > 0:
            risk_interpretation = "样本矩偏度为正;极端正收益概率需结合具体阈值和尾部分布另行估计"
        elif skew_return < 0:
            risk_interpretation = "样本矩偏度为负;极端负收益概率和损失风险需结合尾部分布另行估计"
        else:
            risk_interpretation = "样本矩偏度为零;不能据此判断正负极端收益概率相当"
        
        analysis_results[stock_name] = {
            'returns': returns_pct,
            'mean': mean_return,
            'std': std_return,
            'skewness': skew_return,
            'var_95': var_95,
            'risk_interpretation': risk_interpretation
        }
        
        print(f"\n{stock_name}:")
        print(f"  年化收益率: {mean_return * 252:.2f}%")
        print(f"  年化波动率: {std_return * np.sqrt(252):.2f}%")
        print(f"  偏度: {skew_return:.4f}")
        print(f"  95% VaR: {var_95:.2f}%")
        print(f"  风险特征: {risk_interpretation}")
    
 # 可视化对比
    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(15, 12))
    axes = [ax1, ax2, ax3, ax4]
    
    for i, (stock_name, result) in enumerate(analysis_results.items()):
        returns = result['returns']
        
 # 绘制收益率分布
        axes[i].hist(returns, bins=30, density=True, alpha=0.7, 
                    color=plt.cm.Set1(i), edgecolor='black')
        
 # 标注统计量
        axes[i].axvline(result['mean'], color='red', linestyle='-', 
                       linewidth=2, label=f"均值={result['mean']:.3f}%")
        axes[i].axvline(np.median(returns), color='blue', linestyle='--', 
                       linewidth=2, label=f"中位数={np.median(returns):.3f}%")
        axes[i].axvline(result['var_95'], color='orange', linestyle=':', 
                       linewidth=2, label=f"95% VaR={result['var_95']:.2f}%")
        
 # 拟合正态分布对比
        x_range = np.linspace(returns.min(), returns.max(), 100)
        normal_fit = stats.norm.pdf(x_range, result['mean'], result['std'])
        axes[i].plot(x_range, normal_fit, 'g--', alpha=0.7, 
                    label="正态分布拟合")
        
        axes[i].set_title(f'{stock_name}\n偏度 = {result["skewness"]:.3f}')
        axes[i].set_xlabel('日收益率 (%)')
        axes[i].set_ylabel('密度')
        axes[i].legend()
        axes[i].grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()
    
 # 投资组合偏度分析
    print(f"\n投资组合偏度分析:")
    print("-" * 25)
    
 # 等权重投资组合
    portfolio_returns = np.mean([result['returns'] for result in analysis_results.values()], axis=0)
    portfolio_skew = stats.skew(portfolio_returns)
    
    print(f"等权重投资组合偏度: {portfolio_skew:.4f}")
    
 # 不同权重的影响
    print(f"\n不同权重配置的偏度影响:")
    weight_scenarios = {
        "保守型": [0.6, 0.2, 0.1, 0.1],  # 重配蓝筹股
        "平衡型": [0.25, 0.25, 0.25, 0.25],  # 等权重
        "激进型": [0.1, 0.2, 0.3, 0.4],  # 重配小盘股和科技股
    }
    
    stock_names = list(analysis_results.keys())
    
    for scenario_name, weights in weight_scenarios.items():
        weighted_returns = np.zeros(trading_days)
        for i, (stock_name, weight) in enumerate(zip(stock_names, weights)):
            weighted_returns += weight * analysis_results[stock_name]['returns']
        
        scenario_skew = stats.skew(weighted_returns)
        scenario_var = np.percentile(-weighted_returns, 95)  # 与单资产一致的损失口径VaR
        
        print(f"{scenario_name}: 偏度={scenario_skew:.4f}, 95% VaR={scenario_var:.2f}%")
    
 # 偏度交易策略建议
    print(f"\n基于偏度的投资建议:")
    print("-" * 25)
    print("1. 负偏度资产需要更高的风险溢价补偿")
    print("2. 正偏度资产可能被高估(彩票效应)")
    print("3. 组合构建时考虑偏度分散化")
    print("4. 使用期权等衍生品对冲偏度风险")

financial_skewness_analysis()

2. 业务数据分析

def business_skewness_analysis():
    """电商业务数据的偏度分析"""
    np.random.seed(42)
    
    print("电商业务数据偏度分析:")
    print("=" * 40)
    
 # 模拟电商平台的各种业务数据
    n_customers = 10000
    
 # 不同业务指标的数据生成
    business_data = {
        "订单金额": np.concatenate([
            np.random.lognormal(3.5, 0.8, int(n_customers * 0.8)),  # 普通订单
            np.random.lognormal(6, 0.5, int(n_customers * 0.2))     # 大额订单
        ]),
        
        "客户年龄": np.concatenate([
            np.random.normal(35, 8, int(n_customers * 0.6)),        # 主力客户群
            np.random.normal(22, 3, int(n_customers * 0.3)),        # 年轻客户
            np.random.normal(55, 5, int(n_customers * 0.1))         # 老年客户
        ]),
        
        "月购买次数": np.random.poisson(2.5, n_customers),  # 泊松分布,右偏
        
        "客户评分": np.concatenate([
            1 + np.random.beta(8, 2, int(n_customers * 0.7)) * 4,       # 大多数高评分
            np.random.uniform(1, 5, int(n_customers * 0.3))         # 少数低评分
        ]),
        
        "页面停留时间": np.random.lognormal(2, 1, n_customers)  # 对数正态分布,明显右偏
    }
    
 # 分析每个业务指标
    print("各业务指标偏度分析:")
    print("-" * 30)
    
    skewness_results = {}
    
    for metric_name, data in business_data.items():
 # 演示固定分位数截尾,不等同于异常值识别;保留样本的偏度不能代表原始尾部
        q1, q99 = np.percentile(data, [1, 99])
        clean_data = data[(data >= q1) & (data <= q99)]
        
 # 计算统计量
        mean_val = np.mean(clean_data)
        median_val = np.median(clean_data)
        std_val = np.std(clean_data, ddof=1)
        skew_val = stats.skew(clean_data)
        
 # 业务解释
        if metric_name == "订单金额":
            if skew_val > 1:
                business_insight = "少数大额订单拉高平均值,需关注高价值客户"
            else:
                business_insight = "订单金额分布相对均匀"
        elif metric_name == "客户年龄":
            if abs(skew_val) < 0.5:
                business_insight = "客户年龄样本的矩偏度较低;是否均匀及群体构成需结合分布图和分组占比判断"
            elif skew_val > 0:
                business_insight = "年轻客户占主导,老年客户较少"
            else:
                business_insight = "老年客户占主导,年轻客户较少"
        elif metric_name == "月购买次数":
            if skew_val > 0:
                business_insight = "大多数客户购买频次低,少数客户高频购买"
            else:
                business_insight = "客户购买频次分布相对均匀"
        elif metric_name == "客户评分":
            if skew_val < 0:
                business_insight = "客户满意度较高,但需关注少数不满意客户"
            else:
                business_insight = "客户评分分布需要改善"
        else:  # 页面停留时间
            if skew_val > 1:
                business_insight = "大多数用户浏览时间短,少数用户深度浏览"
            else:
                business_insight = "用户浏览时间分布相对均匀"
        
        skewness_results[metric_name] = {
            'data': clean_data,
            'mean': mean_val,
            'median': median_val,
            'std': std_val,
            'skewness': skew_val,
            'insight': business_insight
        }
        
        print(f"\n{metric_name}:")
        print(f"  均值: {mean_val:.2f}")
        print(f"  中位数: {median_val:.2f}")
        print(f"  偏度: {skew_val:.3f}")
        print(f"  业务洞察: {business_insight}")
    
 # 可视化分析
    fig, axes = plt.subplots(2, 3, figsize=(18, 12))
    axes = axes.flatten()
    
    for i, (metric_name, result) in enumerate(skewness_results.items()):
        if i >= len(axes):
            break
            
        data = result['data']
        
 # 绘制直方图
        axes[i].hist(data, bins=50, density=True, alpha=0.7, 
                    color=plt.cm.Set3(i), edgecolor='black')
        
 # 添加统计线
        axes[i].axvline(result['mean'], color='red', linestyle='-', 
                       linewidth=2, label=f"均值={result['mean']:.1f}")
        axes[i].axvline(result['median'], color='blue', linestyle='--', 
                       linewidth=2, label=f"中位数={result['median']:.1f}")
        
 # 标题和标签
        axes[i].set_title(f'{metric_name}\n偏度 = {result["skewness"]:.3f}')
        
        if metric_name == "订单金额":
            axes[i].set_xlabel('订单金额 (元)')
        elif metric_name == "客户年龄":
            axes[i].set_xlabel('年龄 (岁)')
        elif metric_name == "月购买次数":
            axes[i].set_xlabel('购买次数')
        elif metric_name == "客户评分":
            axes[i].set_xlabel('评分 (1-5分)')
        else:
            axes[i].set_xlabel('停留时间 (分钟)')
        
        axes[i].set_ylabel('密度')
        axes[i].legend()
        axes[i].grid(True, alpha=0.3)
    
 # 删除多余的子图
    if len(skewness_results) < len(axes):
        for j in range(len(skewness_results), len(axes)):
            fig.delaxes(axes[j])
    
    plt.tight_layout()
    plt.show()
    
 # 业务策略建议
    print(f"\n基于偏度分析的业务策略建议:")
    print("=" * 40)
    
    for metric_name, result in skewness_results.items():
        skew_val = result['skewness']
        
        print(f"\n{metric_name}:")
        if metric_name == "订单金额" and skew_val > 1:
            print("  • 针对高价值客户制定专属服务策略")
            print("  • 通过套餐、满减等促销提升客单价")
            print("  • 关注长尾客户的需求挖掘")
        elif metric_name == "客户年龄":
            if skew_val > 0.5:
                print("  • 加强对老年客户群体的开发")
                print("  • 优化产品和服务适应年龄差异")
            elif skew_val < -0.5:
                print("  • 加强对年轻客户群体的开发")
                print("  • 关注新兴消费趋势和偏好")
        elif metric_name == "月购买次数" and skew_val > 1:
            print("  • 识别和维护高频购买客户")
            print("  • 制定客户忠诚度计划")
            print("  • 分析低频客户的购买障碍")
        elif metric_name == "客户评分" and skew_val < -0.5:
            print("  • 重点改善少数低评分订单的问题")
            print("  • 建立客户反馈快速响应机制")
            print("  • 持续优化产品和服务质量")
        elif metric_name == "页面停留时间" and skew_val > 1:
            print("  • 分析深度浏览用户的行为特征")
            print("  • 优化页面设计提高用户参与度")
            print("  • 针对不同浏览深度制定营销策略")
    
 # 客户细分建议
    print(f"\n客户细分建议:")
    print("-" * 15)
    
 # 基于订单金额和购买频次的二维细分
    order_amounts = skewness_results["订单金额"]["data"]
    purchase_freq = skewness_results["月购买次数"]["data"]
    
 # 创建客户价值矩阵
    amount_high = order_amounts > np.percentile(order_amounts, 70)
    freq_high = purchase_freq > np.percentile(purchase_freq, 70)
    
    segment_counts = {
        "高价值高频客户": np.sum(amount_high & freq_high),
        "高价值低频客户": np.sum(amount_high & ~freq_high),
        "低价值高频客户": np.sum(~amount_high & freq_high),
        "低价值低频客户": np.sum(~amount_high & ~freq_high)
    }
    
    for segment, count in segment_counts.items():
        percentage = count / len(order_amounts) * 100
        print(f"{segment}: {count}人 ({percentage:.1f}%)")

business_skewness_analysis()

3. 质量控制中的偏度应用

def quality_control_skewness():
    """质量控制中的偏度分析"""
    np.random.seed(42)
    
    print("产品质量偏度分析:")
    print("=" * 40)
    
 # 模拟不同产品线的质量数据
    n_samples = 1000
    
    quality_data = {
        "A产品线": np.random.normal(100, 2, n_samples),  # 正态分布,符合规格
        
        "B产品线": np.concatenate([
            np.random.normal(100, 1.5, int(n_samples * 0.9)),  # 大部分正常
            np.random.normal(95, 1, int(n_samples * 0.1))      # 少数偏低
        ]),  # 左偏,可能有系统性问题
        
        "C产品线": np.concatenate([
            np.random.normal(100, 1.5, int(n_samples * 0.85)),  # 大部分正常
            np.random.normal(105, 1, int(n_samples * 0.15))     # 少数偏高
        ]),  # 右偏,可能过度加工
        
        "D产品线": np.random.uniform(98, 102, n_samples)  # 模拟均匀分布;仅凭边际分布不能判断过程是否稳定
    }
    
 # 质量规格
    target_value = 100
    lower_spec = 95
    upper_spec = 105
    
    print("质量规格:")
    print(f"目标值: {target_value}")
    print(f"规格范围: [{lower_spec}, {upper_spec}]")
    
 # 分析每条产品线
    quality_results = {}
    
    for product_line, data in quality_data.items():
 # 基本统计
        mean_val = np.mean(data)
        std_val = np.std(data, ddof=1)
        skew_val = stats.skew(data)
        
 # 过程能力分析
        cp = (upper_spec - lower_spec) / (6 * std_val)  # 过程能力
        cpk = min((upper_spec - mean_val) / (3 * std_val), 
                  (mean_val - lower_spec) / (3 * std_val))  # 过程能力指数
        
 # 合格率计算
        within_spec = np.sum((data >= lower_spec) & (data <= upper_spec))
        conformance_rate = within_spec / len(data)
        
 # 偏度对质量的影响分析
        if abs(skew_val) < 0.5:
            skew_impact = "样本矩偏度较低;不能仅凭偏度判断对称性或质量稳定性"
            risk_level = "低"
        elif skew_val > 0.5:
            if np.mean(data > upper_spec) > 0.01:
                skew_impact = "右偏分布,存在过度加工风险"
                risk_level = "中"
            else:
                skew_impact = "右偏分布,但在规格范围内"
                risk_level = "低"
        else:  # skew_val < -0.5
            if np.mean(data < lower_spec) > 0.01:
                skew_impact = "左偏分布,存在不合格品风险"
                risk_level = "高"
            else:
                skew_impact = "左偏分布,但在规格范围内"
                risk_level = "中"
        
        quality_results[product_line] = {
            'data': data,
            'mean': mean_val,
            'std': std_val,
            'skewness': skew_val,
            'cp': cp,
            'cpk': cpk,
            'conformance_rate': conformance_rate,
            'skew_impact': skew_impact,
            'risk_level': risk_level
        }
        
        print(f"\n{product_line}:")
        print(f"  均值: {mean_val:.2f}")
        print(f"  标准差: {std_val:.2f}")
        print(f"  偏度: {skew_val:.3f}")
        print(f"  Cp: {cp:.3f}")
        print(f"  Cpk: {cpk:.3f}")
        print(f"  合格率: {conformance_rate:.1%}")
        print(f"  偏度影响: {skew_impact}")
        print(f"  风险等级: {risk_level}")
    
 # 可视化质量分布
    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(15, 12))
    axes = [ax1, ax2, ax3, ax4]
    
    for i, (product_line, result) in enumerate(quality_results.items()):
        data = result['data']
        
 # 绘制直方图
        axes[i].hist(data, bins=40, density=True, alpha=0.7, 
                    color=plt.cm.Set2(i), edgecolor='black')
        
 # 添加规格线
        axes[i].axvline(target_value, color='green', linestyle='-', 
                       linewidth=2, label=f'目标值={target_value}')
        axes[i].axvline(lower_spec, color='red', linestyle='--', 
                       linewidth=2, label=f'下限={lower_spec}')
        axes[i].axvline(upper_spec, color='red', linestyle='--', 
                       linewidth=2, label=f'上限={upper_spec}')
        axes[i].axvline(result['mean'], color='blue', linestyle=':', 
                       linewidth=2, label=f"均值={result['mean']:.1f}")
        
 # 标注不合格区域
        x_range = np.linspace(data.min(), data.max(), 1000)
        y_range = stats.norm.pdf(x_range, result['mean'], result['std'])
        
 # 填充不合格区域
        x_lower = x_range[x_range < lower_spec]
        if len(x_lower) > 0:
            y_lower = stats.norm.pdf(x_lower, result['mean'], result['std'])
            axes[i].fill_between(x_lower, y_lower, alpha=0.3, color='red')
        
        x_upper = x_range[x_range > upper_spec]
        if len(x_upper) > 0:
            y_upper = stats.norm.pdf(x_upper, result['mean'], result['std'])
            axes[i].fill_between(x_upper, y_upper, alpha=0.3, color='red')
        
        axes[i].set_title(f'{product_line}\n偏度={result["skewness"]:.3f}, Cpk={result["cpk"]:.3f}')
        axes[i].set_xlabel('测量值')
        axes[i].set_ylabel('密度')
        axes[i].legend()
        axes[i].grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()
    
 # 改进建议
    print(f"\n质量改进建议:")
    print("=" * 20)
    
    for product_line, result in quality_results.items():
        print(f"\n{product_line}:")
        
        if result['risk_level'] == "高":
            print("  🚨 紧急改进需要:")
            print("    - 立即调查导致左偏的根本原因")
            print("    - 检查设备校准和工艺参数")
            print("    - 加强过程监控和质量检验")
        elif result['risk_level'] == "中":
            print("  ⚠️  建议改进:")
            if result['skewness'] > 0:
                print("    - 检查是否存在过度加工")
                print("    - 优化工艺参数,避免过量投入")
            else:
                print("    - 监控过程趋势,防止质量下滑")
                print("    - 适当调整工艺参数")
        else:
            print("  ✅ 质量良好:")
            print("    - 维持现有工艺水平")
            print("    - 继续监控过程稳定性")
        
 # 基于Cpk的建议
        if result['cpk'] < 1.0:
            print("    - Cpk偏低,需要提高过程能力")
        elif result['cpk'] < 1.33:
            print("    - Cpk可接受,但仍有提升空间")
        else:
            print("    - Cpk良好,过程能力充足")
    
 # 过程监控建议
    print(f"\n过程监控建议:")
    print("-" * 15)
    print("1. 建立基于偏度的预警系统")
    print("2. 当偏度超过±0.5时触发调查")
    print("3. 结合Cpk和偏度进行综合评估")
    print("4. 定期进行偏度趋势分析")
    print("5. 针对不同偏度类型制定相应的纠正措施")

quality_control_skewness()

🛠️ 实用技巧

1. 偏度的数据预处理

def handle_skewed_data():
    """处理偏斜数据的各种方法"""
    np.random.seed(42)
    
 # 生成强右偏数据
    skewed_data = np.random.lognormal(2, 1, 1000)
    
    print("处理偏斜数据的方法:")
    print("=" * 40)
    
 # 原始数据分析
    original_skew = stats.skew(skewed_data)
    print(f"原始数据偏度: {original_skew:.4f}")
    
 # 方法1: 对数变换
    log_data = np.log(skewed_data)
    log_skew = stats.skew(log_data)
    
 # 方法2: 平方根变换
    sqrt_data = np.sqrt(skewed_data)
    sqrt_skew = stats.skew(sqrt_data)
    
 # 方法3: Box-Cox变换
    from scipy.stats import boxcox
    boxcox_data, lambda_param = boxcox(skewed_data)
    boxcox_skew = stats.skew(boxcox_data)
    
 # 方法4: Yeo-Johnson变换(可处理负值)
    from scipy.stats import yeojohnson
    yj_data, yj_lambda = yeojohnson(skewed_data)
    yj_skew = stats.skew(yj_data)
    
 # 方法5: 分位数变换
    from sklearn.preprocessing import QuantileTransformer
    qt = QuantileTransformer(output_distribution='normal', random_state=42)
    qt_data = qt.fit_transform(skewed_data.reshape(-1, 1)).flatten()
    qt_skew = stats.skew(qt_data)
    
 # 结果对比
    transformations = {
        "原始数据": (skewed_data, original_skew),
        "对数变换": (log_data, log_skew),
        "平方根变换": (sqrt_data, sqrt_skew),
        "Box-Cox变换": (boxcox_data, boxcox_skew),
        "Yeo-Johnson变换": (yj_data, yj_skew),
        "分位数变换": (qt_data, qt_skew)
    }
    
    print(f"\n变换效果对比:")
    print(f"{'方法':<15} {'偏度':<10} {'改善程度':<10}")
    print("-" * 40)
    
    for method, (data, skew_val) in transformations.items():
        improvement = (abs(original_skew) - abs(skew_val)) / abs(original_skew) * 100
        if method == "原始数据":
            print(f"{method:<15} {skew_val:<10.4f} {'--':<10}")
        else:
            print(f"{method:<15} {skew_val:<10.4f} {improvement:<10.1f}%")
    
 # 可视化对比
    fig, axes = plt.subplots(2, 3, figsize=(18, 12))
    axes = axes.flatten()
    
    for i, (method, (data, skew_val)) in enumerate(transformations.items()):
        axes[i].hist(data, bins=30, density=True, alpha=0.7, 
                    color=plt.cm.tab10(i), edgecolor='black')
        axes[i].set_title(f'{method}\n偏度 = {skew_val:.3f}')
        axes[i].set_ylabel('密度')
        axes[i].grid(True, alpha=0.3)
        
 # 添加正态分布拟合
        mean_val = np.mean(data)
        std_val = np.std(data, ddof=1)
        x_range = np.linspace(data.min(), data.max(), 100)
        normal_fit = stats.norm.pdf(x_range, mean_val, std_val)
        axes[i].plot(x_range, normal_fit, 'r--', alpha=0.7, label='正态拟合')
        axes[i].legend()
    
    plt.tight_layout()
    plt.show()
    
 # 变换选择建议
    print(f"\n变换方法选择建议:")
    print("-" * 20)
    print("1. 对数变换: 适用于右偏数据,数据必须为正")
    print("2. 平方根变换: 适用于轻度右偏,数据必须非负")
    print("3. Box-Cox变换: 自动寻找最优变换,数据必须为正")
    print("4. Yeo-Johnson变换: 类似Box-Cox,但可处理负值")
    print("5. 分位数变换: 强制转换为指定分布,但会改变数据关系")
    
    print(f"\n最佳变换参数:")
    print(f"Box-Cox λ = {lambda_param:.4f}")
    print(f"Yeo-Johnson λ = {yj_lambda:.4f}")
    
    return transformations

# 使用函数
transformations = handle_skewed_data()

2. 偏度监控系统

def skewness_monitoring_system():
    """构建偏度监控预警系统"""
    
    class SkewnessMonitor:
        def __init__(self, threshold=0.5, window_size=100):
            self.threshold = threshold
            self.window_size = window_size
            self.data_buffer = []
            self.skewness_history = []
            self.alerts = []
        
        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_skew = stats.skew(self.data_buffer[-self.window_size:])
                self.skewness_history.append(current_skew)
                
 # 检查是否需要预警
                self._check_alert(current_skew)
                
                return current_skew
            return None
        
        def _check_alert(self, current_skew):
            """检查是否触发预警"""
            if abs(current_skew) > self.threshold:
                alert_type = "右偏预警" if current_skew > 0 else "左偏预警"
                self.alerts.append({
                    'timestamp': len(self.skewness_history) - 1,
                    'type': alert_type,
                    'skewness': current_skew,
                    'severity': self._get_severity(current_skew)
                })
        
        def _get_severity(self, skew_val):
            """获取预警严重程度"""
            abs_skew = abs(skew_val)
            if abs_skew > 2:
                return "严重"
            elif abs_skew > 1:
                return "中等"
            else:
                return "轻微"
        
        def get_status(self):
            """获取当前监控状态"""
            if not self.skewness_history:
                return "无数据"
            
            current_skew = self.skewness_history[-1]
            
            if abs(current_skew) <= self.threshold:
                return "正常"
            elif abs(current_skew) <= 1.0:
                return "注意"
            elif abs(current_skew) <= 2.0:
                return "警告"
            else:
                return "严重"
        
        def plot_monitoring(self):
            """绘制监控图表"""
            if not self.skewness_history:
                print("无数据可绘制")
                return
            
            fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))
            
 # 偏度时间序列
            timestamps = range(len(self.skewness_history))
            ax1.plot(timestamps, self.skewness_history, 'b-', linewidth=2, label='偏度')
            ax1.axhline(y=self.threshold, color='orange', linestyle='--', 
                       label=f'预警阈值 ±{self.threshold}')
            ax1.axhline(y=-self.threshold, color='orange', linestyle='--')
            ax1.axhline(y=1, color='red', linestyle=':', alpha=0.7, label='高风险线 ±1')
            ax1.axhline(y=-1, color='red', linestyle=':', alpha=0.7)
            
 # 标记预警点
            for alert in self.alerts:
                color = {'轻微': 'yellow', '中等': 'orange', '严重': 'red'}[alert['severity']]
                ax1.scatter(alert['timestamp'], alert['skewness'], 
                          color=color, s=100, marker='^', 
                          label=f"{alert['type']} ({alert['severity']})")
            
            ax1.set_title('偏度监控时间序列')
            ax1.set_xlabel('时间点')
            ax1.set_ylabel('偏度值')
            ax1.legend()
            ax1.grid(True, alpha=0.3)
            
 # 最近数据分布
            recent_data = self.data_buffer[-self.window_size:]
            ax2.hist(recent_data, bins=30, density=True, alpha=0.7, 
                    color='skyblue', edgecolor='black')
            ax2.set_title(f'最近{len(recent_data)}个数据点的分布')
            ax2.set_xlabel('数值')
            ax2.set_ylabel('密度')
            ax2.grid(True, alpha=0.3)
            
 # 标注当前偏度
            if self.skewness_history:
                current_skew = self.skewness_history[-1]
                ax2.text(0.02, 0.98, f'当前偏度: {current_skew:.3f}', 
                        transform=ax2.transAxes, verticalalignment='top',
                        bbox=dict(boxstyle="round,pad=0.3", facecolor="white", alpha=0.8))
            
            plt.tight_layout()
            plt.show()
        
        def generate_report(self):
            """生成监控报告"""
            print("偏度监控报告")
            print("=" * 30)
            
            if not self.skewness_history:
                print("无监控数据")
                return
            
            current_skew = self.skewness_history[-1]
            status = self.get_status()
            
            print(f"当前状态: {status}")
            print(f"当前偏度: {current_skew:.4f}")
            print(f"监控点数: {len(self.skewness_history)}")
            print(f"预警次数: {len(self.alerts)}")
            
            if self.alerts:
                print(f"\n最近预警:")
                for alert in self.alerts[-3:]:  # 显示最近3次预警
                    print(f"  时间点{alert['timestamp']}: {alert['type']} "
                          f"(偏度={alert['skewness']:.3f}, {alert['severity']})")
    
 # 演示监控系统
    print("偏度监控系统演示:")
    print("=" * 40)
    
 # 创建监控器
    monitor = SkewnessMonitor(threshold=0.5, window_size=50)
    
 # 模拟数据流
    np.random.seed(42)
    
 # 第1阶段:正常数据
    normal_data = np.random.normal(100, 10, 100)
    for data_point in normal_data:
        monitor.add_data(data_point)
    
    print("第1阶段 (正常数据) 完成")
    print(f"状态: {monitor.get_status()}")
    
 # 第2阶段:逐渐变偏
    skewed_data = np.random.lognormal(4.5, 0.3, 100)
    for data_point in skewed_data:
        monitor.add_data(data_point)
    
    print(f"\n第2阶段 (偏斜数据) 完成")
    print(f"状态: {monitor.get_status()}")
    
 # 第3阶段:恢复正常
    recovery_data = np.random.normal(100, 10, 50)
    for data_point in recovery_data:
        monitor.add_data(data_point)
    
    print(f"\n第3阶段 (恢复正常) 完成")
    print(f"状态: {monitor.get_status()}")
    
 # 生成报告和图表
    monitor.generate_report()
    monitor.plot_monitoring()
    
    return monitor

# 使用监控系统
monitor = skewness_monitoring_system()

🔗 相关知识

#统计学 #偏度 #描述性统计 #分布形状 #偏斜程度 #基础