未记录事实核验 · 状态:维护中
记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。
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 💡 **学习建议**
- 理解斯皮尔曼相关系数的非参数特性
- 掌握何时选择斯皮尔曼而非皮尔逊相关系数
- 练习处理有序分类数据的相关分析
- 学会解释并列秩次对结果的影响
- 结合业务场景理解相关性的实际意义
#统计学 #斯皮尔曼相关系数 #秩相关 #非参数统计 #相关分析 #Python统计分析