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

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

warning 适用边界与维护说明

本文适合学习平均秩、斯皮尔曼系数计算、相关方法比较及模拟数据的探索性分析。本次仅作全文结构审阅,未作外部事实核验或代码执行验证;历史导入与多列选择问题已修正。当前价格—评分示例的20个观测仍在基础分析、图示和假设检验中直接依据spearmanr近似p值输出显著性结论,未展示适配的小样本校准,不应据此开展可靠的实际推断。Fisher区间与功效已明确限定为借用公式的演示,不能作为经过验证的斯皮尔曼区间或样本量设计结果。正文“要求单调关系”“实际只能检测单调关系”的表述应理解为该系数主要刻画单调关联,而非计算前必须满足单调关系,低相关也不能排除非单调依赖。满意度、学术排名和金融案例均为模拟数据;边际相关排序不能证明独立贡献、因果重要性或真实业务措施的效果。

🔢 斯皮尔曼相关系数

abstract 📋 本节概览

  • 🎯 学习目标:深入理解斯皮尔曼相关系数的数学原理、计算方法、与皮尔逊相关系数的区别及其在实际数据分析中的应用
  • 📚 前置知识:相关分析|相关分析 | 描述性统计|描述性统计 | 皮尔逊相关系数|皮尔逊相关系数 | 假设检验流程|假设检验流程
  • ⏱️ 预计用时:25分钟
  • 🛠️ 工具准备:Python、NumPy、SciPy、Pandas、Matplotlib、Seaborn

note 📖 **核心定义**

斯皮尔曼相关系数(Spearman's Rank Correlation Coefficient):也称为秩相关系数,是一种非参数统计方法,用于衡量两个变量之间的单调关系强度。它基于变量值的秩次(排序)而非原始数值来计算相关性。

核心特点:不要求数据服从正态分布,适用于有序分类数据和连续数据,对异常值相对稳健。

📐 数学原理与公式

基本公式

note 📊 **斯皮尔曼相关系数公式**

简化公式(无并列秩次时): $$r_s = 1 - \frac{6\sum_{i=1}^n d_i^2}{n(n^2-1)}$$

完整公式(处理并列秩次): $$r_s = \frac{\sum_{i=1}^n (R(X_i) - \bar{R_X})(R(Y_i) - \bar{R_Y})}{\sqrt{\sum_{i=1}^n (R(X_i) - \bar{R_X})^2 \sum_{i=1}^n (R(Y_i) - \bar{R_Y})^2}}$$

其中:

  • $d_i = R(X_i) - R(Y_i)$:第$i$个观测值的秩次差
  • $R(X_i)$:$X_i$在变量$X$中的秩次
  • $R(Y_i)$:$Y_i$在变量$Y$中的秩次
  • $n$:样本量
  • $\bar{R_X}, \bar{R_Y}$:秩次的均值,等于$(n+1)/2$

秩次计算规则

import numpy as np
import pandas as pd
from scipy import stats
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import spearmanr, pearsonr
import warnings
warnings.filterwarnings('ignore')

# 设置中文字体和绘图样式
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
sns.set_style("whitegrid")

def demonstrate_ranking_rules():
    """
    演示秩次计算规则
    """
    print("=== 秩次计算规则演示 ===")
    
 # 示例数据:用户满意度评分
    satisfaction_scores = np.array([4.2, 3.8, 4.5, 3.8, 4.9, 4.2, 3.5, 4.8, 4.2, 4.0])
    
    print(f"原始数据: {satisfaction_scores}")
    print(f"数据排序: {np.sort(satisfaction_scores)}")
    
 # 计算秩次(SciPy方法)
    ranks_scipy = stats.rankdata(satisfaction_scores)
    print(f"SciPy秩次: {ranks_scipy}")
    
 # 手动计算秩次(处理并列值)
    def calculate_ranks_manually(data):
        """
        手动计算秩次,处理并列值
        """
        n = len(data)
 # 创建索引-值对
        indexed_data = [(i, val) for i, val in enumerate(data)]
 # 按值排序
        sorted_data = sorted(indexed_data, key=lambda x: x[1])
        
        ranks = np.zeros(n)
        i = 0
        while i < n:
 # 找到相同值的范围
            j = i
            while j < n and sorted_data[j][1] == sorted_data[i][1]:
                j += 1
            
 # 计算平均秩次
            avg_rank = (i + j + 1) / 2
            
 # 分配秩次
            for k in range(i, j):
                original_index = sorted_data[k][0]
                ranks[original_index] = avg_rank
            
            i = j
        
        return ranks
    
    ranks_manual = calculate_ranks_manually(satisfaction_scores)
    print(f"手动计算秩次: {ranks_manual}")
    
 # 显示秩次分配详情
    print("\n秩次分配详情:")
    df_ranks = pd.DataFrame({
        '原始值': satisfaction_scores,
        'SciPy秩次': ranks_scipy,
        '手动秩次': ranks_manual
    })
    df_ranks['索引'] = range(len(satisfaction_scores))
    df_ranks = df_ranks[['索引', '原始值', 'SciPy秩次', '手动秩次']]
    print(df_ranks)
    
 # 并列值处理说明
    unique_values = np.unique(satisfaction_scores)
    print("\n并列值处理:")
    for val in unique_values:
        indices = np.where(satisfaction_scores == val)[0]
        if len(indices) > 1:
            print(f"值 {val} 出现在位置 {indices},分配平均秩次")
    
    return satisfaction_scores, ranks_scipy

# 执行秩次计算演示
sample_data, sample_ranks = demonstrate_ranking_rules()

💻 Python实现与应用

基础计算示例

def calculate_spearman_manually(x, y):
    """
    手动计算斯皮尔曼相关系数
    """
 # 计算秩次
    rank_x = stats.rankdata(x)
    rank_y = stats.rankdata(y)
    
    n = len(x)
    
 # 方法1:简化公式仅在两变量均无并列秩次时成立;有并列值时不应将该结果作为斯皮尔曼系数
    d_squared = np.sum((rank_x - rank_y) ** 2)
    rho_simple = 1 - (6 * d_squared) / (n * (n**2 - 1))
    
 # 方法2:使用完整公式(标准皮尔逊相关系数应用于秩次)
    mean_rank_x = np.mean(rank_x)
    mean_rank_y = np.mean(rank_y)
    
    numerator = np.sum((rank_x - mean_rank_x) * (rank_y - mean_rank_y))
    denominator = np.sqrt(np.sum((rank_x - mean_rank_x)**2) * np.sum((rank_y - mean_rank_y)**2))
    rho_full = numerator / denominator
    
    return rho_simple, rho_full, rank_x, rank_y

def comprehensive_spearman_analysis():
    """
    全面的斯皮尔曼相关分析
    """
    print("\n=== 斯皮尔曼相关系数计算演示 ===")
    
 # 示例数据:电商平台商品评价数据
    np.random.seed(42)
    n = 20
    
 # 商品价格(元)
    price = np.random.uniform(50, 500, n)
    
 # 用户评分(1-5分)- 与价格存在非线性关系
 # 中等价格商品评分最高
    rating_base = 3 + 2 * np.exp(-(price - 200)**2 / 10000)
    rating = rating_base + np.random.normal(0, 0.3, n)
    rating = np.clip(rating, 1, 5)  # 限制在1-5分范围内
    
    print("商品评价数据:")
    print(f"价格范围: {price.min():.1f} - {price.max():.1f} 元")
    print(f"评分范围: {rating.min():.2f} - {rating.max():.2f} 分")
    
 # 计算相关系数
 # 手动计算
    rho_simple, rho_full, rank_price, rank_rating = calculate_spearman_manually(price, rating)
    
 # SciPy计算
    rho_scipy, p_value = spearmanr(price, rating)
    
 # 皮尔逊相关系数作为对比
    pearson_r, pearson_p = pearsonr(price, rating)
    
    print(f"\n相关系数计算结果:")
    print(f"手动计算(简化公式): {rho_simple:.4f}")
    print(f"手动计算(完整公式): {rho_full:.4f}")
    print(f"SciPy计算: {rho_scipy:.4f} (p值: {p_value:.6f})")
    print(f"皮尔逊相关系数: {pearson_r:.4f} (p值: {pearson_p:.6f})")
    
 # 显示详细的秩次信息
    print(f"\n秩次对比表:")
    df_detailed = pd.DataFrame({
        '商品ID': range(1, n+1),
        '价格': price,
        '评分': rating,
        '价格秩次': rank_price,
        '评分秩次': rank_rating,
        '秩次差': rank_price - rank_rating,
        '秩次差平方': (rank_price - rank_rating)**2
    })
    
 # 显示前10个商品的详细信息
    print(df_detailed.head(10).round(2))
    
 # 解释结果
    print(f"\n📊 结果解释:")
    
 # 相关强度判断
    abs_rho = abs(rho_scipy)
    if abs_rho >= 0.7:
        strength = "强相关"
    elif abs_rho >= 0.4:
        strength = "中等相关"
    elif abs_rho >= 0.2:
        strength = "弱相关"
    else:
        strength = "几乎无相关"
    
    direction = "正相关" if rho_scipy > 0 else "负相关"
    
    print(f"• 斯皮尔曼相关系数 {rho_scipy:.4f} 表明价格与评分呈 {direction},强度为 {strength}")
    print(f"• p值 {p_value:.6f} {'< 0.05,相关性统计显著' if p_value < 0.05 else '>= 0.05,相关性不显著'}")
    
 # 与皮尔逊相关系数的比较
    print(f"\n🔍 与皮尔逊相关系数的比较:")
    print(f"• 皮尔逊相关系数: {pearson_r:.4f}")
    print(f"• 斯皮尔曼相关系数: {rho_scipy:.4f}")
    print(f"• 差异: {abs(pearson_r - rho_scipy):.4f}")
    
    if abs(pearson_r - rho_scipy) > 0.1:
        print("• 两个系数差异较大,可能存在非线性关系或异常值")
    else:
        print("• 两个系数相近,但仅凭这一点不能判断关系是否线性,应结合散点图检查")
    
    return price, rating, df_detailed

# 执行斯皮尔曼相关分析
price_data, rating_data, detailed_df = comprehensive_spearman_analysis()

可视化展示

def visualize_spearman_correlation(x, y, title="斯皮尔曼相关分析"):
    """
    可视化斯皮尔曼相关性分析
    """
    fig, axes = plt.subplots(2, 2, figsize=(15, 12))
    fig.suptitle(title, fontsize=16, fontweight='bold')
    
 # 计算相关系数和秩次
    rho_spearman, p_spearman = spearmanr(x, y)
    rho_pearson, p_pearson = pearsonr(x, y)
    rank_x = stats.rankdata(x)
    rank_y = stats.rankdata(y)
    
 # 1. 原始数据散点图
    axes[0, 0].scatter(x, y, alpha=0.7, s=60, color='blue')
    axes[0, 0].set_xlabel('X变量(原始值)')
    axes[0, 0].set_ylabel('Y变量(原始值)')
    axes[0, 0].set_title(f'原始数据散点图\n皮尔逊相关系数: {rho_pearson:.3f}')
    
 # 添加拟合线
    z = np.polyfit(x, y, 1)
    p = np.poly1d(z)
    axes[0, 0].plot(x, p(x), "r--", alpha=0.8, linewidth=2)
    axes[0, 0].grid(True, alpha=0.3)
    
 # 2. 秩次散点图
    axes[0, 1].scatter(rank_x, rank_y, alpha=0.7, s=60, color='red')
    axes[0, 1].set_xlabel('X变量(秩次)')
    axes[0, 1].set_ylabel('Y变量(秩次)')
    axes[0, 1].set_title(f'秩次散点图\n斯皮尔曼相关系数: {rho_spearman:.3f}')
    
 # 添加秩次拟合线
    z_rank = np.polyfit(rank_x, rank_y, 1)
    p_rank = np.poly1d(z_rank)
    axes[0, 1].plot(rank_x, p_rank(rank_x), "r--", alpha=0.8, linewidth=2)
    axes[0, 1].grid(True, alpha=0.3)
    
 # 3. 相关系数对比
    axes[1, 0].axis('off')
    comparison_text = f"""
    相关系数对比分析:
    
    皮尔逊相关系数: {rho_pearson:.4f}
    p值: {p_pearson:.6f}
    
    斯皮尔曼相关系数: {rho_spearman:.4f}
    p值: {p_spearman:.6f}
    
    差异: {abs(rho_pearson - rho_spearman):.4f}
    
    解释:
    {'• 两系数相近,仍需结合散点图判断关系形态' if abs(rho_pearson - rho_spearman) < 0.1 else '• 两系数差异较大,需结合散点图检查非线性关系和异常值'}
    {'• 相关性统计显著' if p_spearman < 0.05 else '• 相关性不显著'}
    
    适用场景:
    • 皮尔逊: 衡量线性关联,计算本身不要求正态分布;推断需另查假设
    • 斯皮尔曼: 衡量单调关联,不要求正态分布;推断仍有适用条件
    """
    
    axes[1, 0].text(0.1, 0.9, comparison_text, fontsize=12, verticalalignment='top',
                   bbox=dict(boxstyle="round,pad=0.3", facecolor="lightblue", alpha=0.8))
    
 # 4. 秩次差分析
    rank_diff = rank_x - rank_y
    axes[1, 1].bar(range(len(rank_diff)), rank_diff, alpha=0.7, color='green')
    axes[1, 1].axhline(y=0, color='red', linestyle='--', alpha=0.8)
    axes[1, 1].set_xlabel('观测点索引')
    axes[1, 1].set_ylabel('秩次差 (X秩次 - Y秩次)')
    axes[1, 1].set_title(f'秩次差分布\n平均绝对秩次差: {np.mean(np.abs(rank_diff)):.2f}')
    axes[1, 1].grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()
    
    return rho_spearman, rho_pearson

# 可视化价格-评分关系
spearman_coef, pearson_coef = visualize_spearman_correlation(
    price_data, rating_data, "电商商品价格与评分相关性分析"
)

🔍 与皮尔逊相关系数的比较

适用条件对比

def compare_correlation_methods():
    """
    比较不同类型数据下皮尔逊和斯皮尔曼相关系数的表现
    """
    print("\n=== 皮尔逊 vs 斯皮尔曼相关系数比较 ===")
    
    np.random.seed(123)
    n = 100
    
 # 创建不同类型的数据
    test_cases = {
        '线性关系': {
            'x': np.random.normal(0, 1, n),
            'y_func': lambda x: 2 * x + np.random.normal(0, 0.5, len(x))
        },
        '非线性关系(指数)': {
            'x': np.random.uniform(0, 3, n),
            'y_func': lambda x: np.exp(x) + np.random.normal(0, 0.5, len(x))
        },
        '非线性关系(对数)': {
            'x': np.random.uniform(1, 10, n),
            'y_func': lambda x: np.log(x) + np.random.normal(0, 0.2, len(x))
        },
        '含异常值': {
            'x': np.random.normal(0, 1, n),
            'y_func': lambda x: x + np.random.normal(0, 0.3, len(x))
        },
        '单调但非线性': {
            'x': np.random.uniform(0, 10, n),
            'y_func': lambda x: x**0.5 + np.random.normal(0, 0.3, len(x))
        }
    }
    
    print(f"{'数据类型':<15} {'皮尔逊':<10} {'斯皮尔曼':<10} {'差异':<8} {'推荐方法':<15}")
    print("-" * 65)
    
    results = {}
    
    for case_name, case_data in test_cases.items():
        x = case_data['x']
        y = case_data['y_func'](x)
        
 # 为含异常值数据添加异常值
        if case_name == '含异常值':
            outlier_indices = np.random.choice(n, 5, replace=False)
            y[outlier_indices] += np.random.choice([-5, 5], 5)
        
 # 计算相关系数
        pearson_r, _ = pearsonr(x, y)
        spearman_r, _ = spearmanr(x, y)
        
        diff = abs(pearson_r - spearman_r)
        
 # 推荐方法
        recommendation = "结合研究目标、尺度和散点图选择"
        
        print(f"{case_name:<15} {pearson_r:<10.3f} {spearman_r:<10.3f} {diff:<8.3f} {recommendation:<15}")
        
        results[case_name] = {
            'x': x, 'y': y, 
            'pearson': pearson_r, 'spearman': spearman_r,
            'recommendation': recommendation
        }
    
 # 总结建议
    print(f"\n💡 选择建议:")
    print("• 目标是衡量线性关联 → 可考虑皮尔逊相关系数;计算本身不要求正态分布,推断需另查假设")
    print("• 单调非线性关系 → 斯皮尔曼相关系数")
    print("• 含异常值数据 → 斯皮尔曼相关系数(更稳健)")
    print("• 顺序型数据 → 斯皮尔曼相关系数")
    print("• 不确定时 → 两个都计算并比较")
    
    return results

# 执行相关系数比较
comparison_results = compare_correlation_methods()

🏢 实际应用场景

1. 市场研究中的顾客满意度分析

def customer_satisfaction_analysis():
    """
    顾客满意度调查中的斯皮尔曼相关分析
    """
    print("\n=== 顾客满意度调查分析 ===")
    
 # 模拟顾客满意度调查数据
    np.random.seed(456)
    n_customers = 200
    
 # 生成调查数据(1-5分制)
    service_quality = np.random.randint(1, 6, n_customers)  # 服务质量评分
    product_quality = np.random.randint(1, 6, n_customers)  # 产品质量评分
    price_satisfaction = np.random.randint(1, 6, n_customers)  # 价格满意度
    
 # 总体满意度(与其他因素相关但有随机性)
    overall_satisfaction = np.round(
        0.4 * service_quality + 0.35 * product_quality + 0.25 * price_satisfaction + 
        np.random.normal(0, 0.5, n_customers)
    ).astype(int)
    overall_satisfaction = np.clip(overall_satisfaction, 1, 5)
    
 # 创建数据框
    df_survey = pd.DataFrame({
        '服务质量': service_quality,
        '产品质量': product_quality,
        '价格满意度': price_satisfaction,
        '总体满意度': overall_satisfaction
    })
    
    print("顾客满意度调查数据概况:")
    print(df_survey.describe())
    
 # 计算各因素间的斯皮尔曼相关系数
    factors = ['服务质量', '产品质量', '价格满意度']
    
    print(f"\n各因素与总体满意度的相关性分析:")
    print(f"{'因素':<10} {'斯皮尔曼系数':<12} {'p值':<12} {'相关强度':<12}")
    print("-" * 50)
    
    correlations = {}
    for factor in factors:
        rho, p_val = spearmanr(df_survey[factor], df_survey['总体满意度'])
        
 # 相关强度判断
        if abs(rho) >= 0.7:
            strength = "强相关"
        elif abs(rho) >= 0.4:
            strength = "中等相关"
        elif abs(rho) >= 0.2:
            strength = "弱相关"
        else:
            strength = "几乎无关"
        
        print(f"{factor:<10} {rho:<12.3f} {p_val:<12.6f} {strength:<12}")
        correlations[factor] = rho
    
 # 因素重要性排序
    sorted_factors = sorted(correlations.items(), key=lambda x: abs(x[1]), reverse=True)
    
    print(f"\n📊 模拟样本中的边际相关强度排序(不代表因果重要性):")
    for i, (factor, corr) in enumerate(sorted_factors, 1):
        print(f"{i}. {factor}: {corr:.3f}")
    
 # 业务建议
    print(f"\n💼 业务改进建议:")
    top_factor = sorted_factors[0][0]
    print(f"• '{top_factor}' 在该模拟样本中与总体满意度的边际相关性最强,可作为进一步调查候选,不能据此直接确定改进优先级")
    
    if correlations['服务质量'] > 0.5:
        print("• 该模拟样本中服务质量与总体满意度的秩相关系数超过0.5,可作为进一步调查候选;这不能证明员工培训会提高满意度")
    if correlations['产品质量'] > 0.5:
        print("• 该模拟样本中产品质量与满意度的秩相关系数超过0.5;是否存在因果影响及提升产品标准是否有效,需另行研究")
    if correlations['价格满意度'] > 0.3:
        print("• 该模拟样本中价格满意度与总体满意度的秩相关系数超过0.3,可进一步研究价格体验;这不能直接支持调整定价或增加性价比的措施")
    
    return df_survey, correlations

# 执行顾客满意度分析
survey_data, satisfaction_correlations = customer_satisfaction_analysis()

2. 学术研究中的排名数据分析

def academic_ranking_analysis():
    """
    学术研究排名数据的斯皮尔曼相关分析
    """
    print("\n=== 学术期刊排名相关性分析 ===")
    
 # 模拟学术期刊数据
    np.random.seed(789)
    n_journals = 50
    
 # 生成期刊评价指标(排名数据)
    impact_factor_rank = np.arange(1, n_journals + 1)
    np.random.shuffle(impact_factor_rank)  # 影响因子排名
    
 # 其他排名与影响因子排名相关但有差异
    citation_rank = impact_factor_rank + np.random.randint(-5, 6, n_journals)
    citation_rank = np.clip(citation_rank, 1, n_journals)
    
    h_index_rank = impact_factor_rank + np.random.randint(-8, 9, n_journals)
    h_index_rank = np.clip(h_index_rank, 1, n_journals)
    
 # 创建期刊数据
    df_journals = pd.DataFrame({
        '期刊ID': [f'Journal_{i:02d}' for i in range(1, n_journals + 1)],
        '影响因子排名': impact_factor_rank,
        '引用次数排名': citation_rank,
        'H指数排名': h_index_rank
    })
    
    print("学术期刊排名数据示例:")
    print(df_journals.head(10))
    
 # 计算排名间的斯皮尔曼相关系数
    ranking_columns = ['影响因子排名', '引用次数排名', 'H指数排名']
    correlation_matrix = df_journals[ranking_columns].corr(method='spearman')
    
    print(f"\n排名指标间的斯皮尔曼相关矩阵:")
    print(correlation_matrix.round(3))
    
 # 详细分析各指标间的关系
    print(f"\n详细相关性分析:")
    
    pairs = [
        ('影响因子排名', '引用次数排名'),
        ('影响因子排名', 'H指数排名'),
        ('引用次数排名', 'H指数排名')
    ]
    
    for col1, col2 in pairs:
        rho, p_val = spearmanr(df_journals[col1], df_journals[col2])
        print(f"{col1} vs {col2}:")
        print(f"  斯皮尔曼相关系数: {rho:.4f}")
        print(f"  p值: {p_val:.6f}")
        print(f"  解释: {'排名高度一致' if rho > 0.8 else '排名中等一致' if rho > 0.5 else '排名一致性较低'}")
        print()
    
 # 识别排名差异较大的期刊
    df_journals['影响因子_引用差异'] = abs(df_journals['影响因子排名'] - df_journals['引用次数排名'])
    df_journals['影响因子_H指数差异'] = abs(df_journals['影响因子排名'] - df_journals['H指数排名'])
    
    print("排名差异最大的期刊(前5名):")
    print("影响因子排名 vs 引用次数排名:")
    top_diff_citation = df_journals.nlargest(5, '影响因子_引用差异')[['期刊ID', '影响因子排名', '引用次数排名', '影响因子_引用差异']]
    print(top_diff_citation)
    
    print("\n影响因子排名 vs H指数排名:")
    top_diff_h = df_journals.nlargest(5, '影响因子_H指数差异')[['期刊ID', '影响因子排名', 'H指数排名', '影响因子_H指数差异']]
    print(top_diff_h)
    
    return df_journals, correlation_matrix

# 执行学术排名分析
journal_data, ranking_correlations = academic_ranking_analysis()

3. 金融数据中的风险评估

def financial_risk_assessment():
    """
    金融风险评估中的斯皮尔曼相关分析
    """
    print("\n=== 金融风险评估相关性分析 ===")
    
 # 模拟金融风险评估数据
    np.random.seed(999)
    n_companies = 100
    
 # 生成公司风险评估数据
    credit_score = np.random.normal(650, 80, n_companies)  # 信用评分
    debt_ratio = np.random.beta(2, 5, n_companies)  # 负债率
    profitability = np.random.exponential(0.1, n_companies)  # 盈利能力
    market_volatility = np.random.gamma(2, 0.1, n_companies)  # 市场波动性
    
 # 风险等级(1-10,10为最高风险)
 # 基于其他指标计算,但添加非线性关系
    risk_level = (
        5 + 
        -2 * (credit_score - 650) / 80 +  # 信用评分越高风险越低
        3 * debt_ratio +  # 负债率越高风险越高
        -1.5 * np.log(profitability + 0.01) +  # 盈利能力与风险非线性关系
        2 * market_volatility +  # 市场波动性增加风险
        np.random.normal(0, 0.5, n_companies)  # 随机噪声
    )
    risk_level = np.clip(risk_level, 1, 10)
    
 # 创建数据框
    df_financial = pd.DataFrame({
        '公司ID': [f'Company_{i:03d}' for i in range(1, n_companies + 1)],
        '信用评分': credit_score,
        '负债率': debt_ratio,
        '盈利能力': profitability,
        '市场波动性': market_volatility,
        '风险等级': risk_level
    })
    
    print("金融风险评估数据概况:")
    print(df_financial.describe().round(3))
    
 # 计算各风险因子与风险等级的相关性
    risk_factors = ['信用评分', '负债率', '盈利能力', '市场波动性']
    
    print(f"\n各风险因子与风险等级的相关性:")
    print(f"{'风险因子':<12} {'皮尔逊':<10} {'斯皮尔曼':<12} {'差异':<8} {'推荐':<10}")
    print("-" * 55)
    
    for factor in risk_factors:
        pearson_r, _ = pearsonr(df_financial[factor], df_financial['风险等级'])
        spearman_r, p_val = spearmanr(df_financial[factor], df_financial['风险等级'])
        diff = abs(pearson_r - spearman_r)
        
        recommendation = "需结合研究目标与关系形态判断"
        
        print(f"{factor:<12} {pearson_r:<10.3f} {spearman_r:<12.3f} {diff:<8.3f} {recommendation:<10}")
    
 # 风险因子重要性分析
    spearman_correlations = {}
    for factor in risk_factors:
        rho, _ = spearmanr(df_financial[factor], df_financial['风险等级'])
        spearman_correlations[factor] = abs(rho)  # 使用绝对值表示该模拟样本中的边际秩相关强度,不代表重要性或独立贡献
    
    sorted_importance = sorted(spearman_correlations.items(), key=lambda x: x[1], reverse=True)
    
    print(f"\n模拟样本中的风险因子边际相关强度排序(不代表独立贡献或因果重要性):")
    for i, (factor, importance) in enumerate(sorted_importance, 1):
        print(f"{i}. {factor}: {importance:.3f}")
    
 # 风险管理建议
    print(f"\n🎯 风险管理建议:")
    top_factor = sorted_importance[0][0]
    print(f"• 该模拟样本中与风险等级边际相关最强的因子: {top_factor},不等于真实业务中的最重要风险因子")
    
    if spearman_correlations['负债率'] > 0.5:
        print("• 该模拟样本中负债率与风险等级的秩相关绝对值超过0.5,可作为进一步研究候选;这不能直接支持设置负债率上限")
    if spearman_correlations['信用评分'] > 0.3:
        print("• 该模拟样本中信用评分与风险等级的秩相关绝对值超过0.3;这不能证明因果影响,也不能直接支持信用评分准入门槛")
    if spearman_correlations['市场波动性'] > 0.4:
        print("• 该模拟样本中市场波动性与风险等级的秩相关绝对值超过0.4,可进一步研究其关联;这不能直接证明增强风险对冲措施有效")
    
    return df_financial, spearman_correlations

# 执行金融风险评估
financial_data, risk_correlations = financial_risk_assessment()

📊 高级应用技巧

假设检验与置信区间

def spearman_hypothesis_testing():
    """
    斯皮尔曼相关系数的假设检验
    """
    print("\n=== 斯皮尔曼相关系数假设检验 ===")
    
 # 使用之前的价格-评分数据
    x, y = price_data, rating_data
    n = len(x)
    
 # 计算斯皮尔曼相关系数
    rho, p_value = spearmanr(x, y)
    
    print(f"样本信息:")
    print(f"样本量: {n}")
    print(f"斯皮尔曼相关系数: {rho:.4f}")
    print(f"p值: {p_value:.6f}")
    
 # 假设检验
    alpha = 0.05
    print(f"\n假设检验 (α = {alpha}):")
    print(f"H0: 总体斯皮尔曼秩相关系数 ρ_s = 0(不等于不存在任何关系)")
    print(f"H1: 总体斯皮尔曼秩相关系数 ρ_s ≠ 0")
    
    if p_value < alpha:
        print(f"✅ p值 {p_value:.6f} < α {alpha},拒绝H0,存在显著相关性")
    else:
        print(f"❌ p值 {p_value:.6f} ≥ α {alpha},不能拒绝H0,无显著相关性")
    
 # 计算置信区间(使用Fisher变换的近似方法)
    def fisher_transform(r):
        return 0.5 * np.log((1 + r) / (1 - r))
    
    def inverse_fisher_transform(z):
        return (np.exp(2 * z) - 1) / (np.exp(2 * z) + 1)
    
 # Fisher变换
    z_rho = fisher_transform(rho)
    se_z = 1 / np.sqrt(n - 3)  # 借用Fisher变换的近似标准误;不能视为通用的斯皮尔曼标准误
    
 # 95%置信区间
    z_alpha = stats.norm.ppf(1 - alpha/2)
    z_lower = z_rho - z_alpha * se_z
    z_upper = z_rho + z_alpha * se_z
    
 # 转换回相关系数
    ci_lower = inverse_fisher_transform(z_lower)
    ci_upper = inverse_fisher_transform(z_upper)
    
    print(f"\n借用Fisher变换的名义95%近似区间演示(未保证斯皮尔曼覆盖率):")
    print(f"[{ci_lower:.4f}, {ci_upper:.4f}]")
    print("解释: 这是借用Fisher变换计算的近似区间示例,未保证对当前斯皮尔曼分析具有95%覆盖率;小样本或较多并列值时需另选适配方法")
    
 # 效应量评估
    print(f"\n效应量评估:")
    abs_rho = abs(rho)
    if abs_rho < 0.1:
        effect_size = "极小效应"
    elif abs_rho < 0.3:
        effect_size = "小效应"
    elif abs_rho < 0.5:
        effect_size = "中等效应"
    else:
        effect_size = "大效应"
    
    print(f"相关系数绝对值: {abs_rho:.4f}")
    print(f"效应量: {effect_size}")
    
 # 功效分析(样本量对检验功效的影响)
    print(f"\n功效分析:")
    sample_sizes = [10, 20, 30, 50, 100, 200]
    true_rho = 0.3  # 假设真实相关系数为0.3
    
    print(f"假设真实秩相关系数为{true_rho},借用Fisher正态近似得到的功效演示值(非经验证的斯皮尔曼样本量设计结果):")
    print(f"{'样本量':<8} {'功效':<8}")
    print("-" * 20)
    
    for n_sample in sample_sizes:
 # 使用近似公式计算功效
        z_true = fisher_transform(true_rho)
        se_sample = 1 / np.sqrt(n_sample - 3)
        z_critical = stats.norm.ppf(1 - alpha/2)
        
 # 功效计算
        power = 1 - stats.norm.cdf(z_critical - z_true/se_sample) + stats.norm.cdf(-z_critical - z_true/se_sample)
        print(f"{n_sample:<8} {power:<8.3f}")
    
    return rho, ci_lower, ci_upper

# 执行假设检验
rho_result, ci_low, ci_high = spearman_hypothesis_testing()

处理并列秩次的影响

def tied_ranks_analysis():
    """
    分析并列秩次对斯皮尔曼相关系数的影响
    """
    print("\n=== 并列秩次影响分析 ===")
    
 # 创建含有大量并列值的数据
    np.random.seed(666)
    n = 50
    
 # 生成离散化数据(模拟Likert量表)
    x_continuous = np.random.normal(3, 1.2, n)
    y_continuous = 0.8 * x_continuous + np.random.normal(0, 0.5, n)
    
 # 离散化为1-5分制
    x_discrete = np.round(np.clip(x_continuous, 1, 5)).astype(int)
    y_discrete = np.round(np.clip(y_continuous, 1, 5)).astype(int)
    
    print("数据并列情况分析:")
    print("\nX变量值分布:")
    x_counts = pd.Series(x_discrete).value_counts().sort_index()
    print(x_counts)
    
    print("\nY变量值分布:")
    y_counts = pd.Series(y_discrete).value_counts().sort_index()
    print(y_counts)
    
 # 计算不同情况下的相关系数
    print(f"\n相关系数比较:")
    
 # 连续数据
    rho_continuous, _ = spearmanr(x_continuous, y_continuous)
    pearson_continuous, _ = pearsonr(x_continuous, y_continuous)
    
 # 离散数据
    rho_discrete, _ = spearmanr(x_discrete, y_discrete)
    pearson_discrete, _ = pearsonr(x_discrete, y_discrete)
    
    print(f"{'数据类型':<12} {'皮尔逊':<10} {'斯皮尔曼':<12}")
    print("-" * 35)
    print(f"{'连续数据':<12} {pearson_continuous:<10.4f} {rho_continuous:<12.4f}")
    print(f"{'离散数据':<12} {pearson_discrete:<10.4f} {rho_discrete:<12.4f}")
    
 # 分析并列秩次的调整
    print(f"\n并列秩次处理:")
    
 # 计算秩次
    ranks_x = stats.rankdata(x_discrete)
    ranks_y = stats.rankdata(y_discrete)
    
    print(f"X变量秩次示例: {ranks_x[:10]}")
    print(f"Y变量秩次示例: {ranks_y[:10]}")
    
 # 显示并列秩次的平均值分配
    unique_x = np.unique(x_discrete)
    print(f"\nX变量并列秩次分配:")
    for val in unique_x:
        indices = np.where(x_discrete == val)[0]
        if len(indices) > 1:
            assigned_ranks = ranks_x[indices]
            print(f"值 {val}: 出现{len(indices)}次,分配秩次 {assigned_ranks[0]:.1f}")
    
 # 计算并列值对相关系数的影响
    print(f"\n💡 并列秩次影响总结:")
    impact = abs(rho_continuous - rho_discrete)
    print(f"相关系数变化: {impact:.4f}")
    
    if impact < 0.05:
        print("• 并列秩次对相关系数影响很小")
    elif impact < 0.1:
        print("• 并列秩次对相关系数有轻微影响")
    else:
        print("• 并列秩次对相关系数影响较大,需要注意")
    
    print("• 大量并列值会降低斯皮尔曼相关系数的区分能力")
    print("• 建议在可能的情况下使用更精细的测量量表")
    
    return x_discrete, y_discrete, rho_discrete

# 执行并列秩次分析
tied_x, tied_y, tied_rho = tied_ranks_analysis()

⚠️ 注意事项与最佳实践

warning 🚨 **斯皮尔曼相关系数注意事项**

适用条件:

  • 数据至少为顺序尺度
  • 要求单调关系(不一定线性)
  • 对异常值相对稳健

常见误区:

  • 误认为可以检测任何类型的关系(实际只能检测单调关系)
  • 忽视大量并列值对结果的影响
  • 将相关性等同于因果关系
  • 不考虑样本量对检验功效的影响

最佳实践:

  • 先进行数据探索性分析,了解数据分布
  • 同时计算皮尔逊和斯皮尔曼相关系数进行比较
  • 结合散点图进行可视化分析
  • 报告置信区间而非仅仅点估计
  • 考虑多重比较问题的调整

📚 扩展学习资源

理论深化

  • 📖 《非参数统计》 - 霍兰德·沃尔夫
  • 📖 《Practical Statistics for Data Scientists》 - Bruce & Bruce
  • 🎓 在线课程:Coursera《Statistics with R》

实践工具

  • 🐍 Python库:SciPy、Pandas、Statsmodels
  • 📊 可视化:Matplotlib、Seaborn、Plotly
  • 🔧 专业软件:R、SPSS、SAS

进阶主题

  • 皮尔逊相关系数 - 参数相关分析方法
  • 肯德尔相关系数 - 另一种秩相关方法
  • 偏相关分析 - 控制其他变量的相关分析

tip 💡 **学习建议**

  1. 理解斯皮尔曼相关系数的非参数特性
  2. 掌握何时选择斯皮尔曼而非皮尔逊相关系数
  3. 练习处理有序分类数据的相关分析
  4. 学会解释并列秩次对结果的影响
  5. 结合业务场景理解相关性的实际意义

#统计学 #斯皮尔曼相关系数 #秩相关 #非参数统计 #相关分析 #Python统计分析