Python 数据分析实战:5种数据类型相关性检验与可视化代码全解

在数据科学项目中,理解变量间的相关性是探索性分析的核心环节。本文将深入解析Python中处理五种常见数据类型组合的相关性分析方法,提供可直接复用的代码模板,涵盖统计检验、可视化技巧和实际应用场景。

1. 连续变量 vs 连续变量

当分析两个连续变量的关系时,散点图和Pearson相关系数是标准工具。但实际应用中需要注意数据分布和异常值的影响。

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
from scipy import stats

# 生成示例数据
np.random.seed(42)
data = pd.DataFrame({
    '销售额': np.random.normal(100, 15, 200),
    '广告投入': np.random.normal(50, 8, 200) * 1.2 + np.random.normal(0, 5, 200)
})

# 增强型散点图
plt.figure(figsize=(10,6))
sns.scatterplot(data=data, x='广告投入', y='销售额', 
                alpha=0.6, edgecolor='w', s=80)
plt.title('销售额与广告投入关系', pad=20, fontsize=14)
sns.regplot(data=data, x='广告投入', y='销售额', 
           scatter=False, color='red', ci=95)
plt.grid(True, alpha=0.3)

# 计算相关系数及p值
corr, p_value = stats.pearsonr(data['广告投入'], data['销售额'])
print(f"Pearson r = {corr:.3f}, p-value = {p_value:.4f}")

提示:当数据量较大时,考虑使用hexbin图或密度图替代散点图以避免过度绘制问题

对于非正态分布数据,Spearman相关系数是更好的选择:

# 非参数检验
spearman_corr = data.corr(method='spearman').iloc[0,1]
print(f"Spearman ρ = {spearman_corr:.3f}")

2. 连续变量 vs 分类变量

分析分类变量如何影响连续变量时,箱线图配合统计检验能直观展示组间差异。

2.1 二分类情况

# 模拟电商用户数据
user_data = pd.DataFrame({
    '消费金额': np.concatenate([
        np.random.normal(800, 150, 100),
        np.random.normal(1200, 200, 100)
    ]),
    '会员等级': ['普通']*100 + ['VIP']*100
})

# 增强箱线图
plt.figure(figsize=(8,6))
sns.boxplot(data=user_data, x='会员等级', y='消费金额', 
           width=0.4, palette='pastel')
sns.stripplot(data=user_data, x='会员等级', y='消费金额',
             color='black', alpha=0.3, size=4)
plt.title('不同会员等级的消费金额分布', pad=15)

# 独立样本t检验
normal = user_data[user_data['会员等级']=='普通']['消费金额']
vip = user_data[user_data['会员等级']=='VIP']['消费金额']
t_stat, p_val = stats.ttest_ind(normal, vip, equal_var=False)
print(f"Welch's t-test: t = {t_stat:.2f}, p = {p_val:.4f}")

2.2 多分类情况

对于三个及以上分类,使用ANOVA分析:

# 添加第三组数据
user_data = pd.concat([
    user_data,
    pd.DataFrame({
        '消费金额': np.random.normal(1500, 250, 100),
        '会员等级': ['SVIP']*100
    })
])

# 可视化
plt.figure(figsize=(10,6))
sns.violinplot(data=user_data, x='会员等级', y='消费金额',
              palette='Set2', inner='quartile')
plt.title('多等级用户消费金额分布', pad=15)

# 单因素方差分析
groups = [group['消费金额'] for name, group in user_data.groupby('会员等级')]
f_stat, p_val = stats.f_oneway(*groups)
print(f"ANOVA: F = {f_stat:.2f}, p = {p_val:.4f}")

# 事后检验(Tukey HSD)
from statsmodels.stats.multicomp import pairwise_tukeyhsd
tukey = pairwise_tukeyhsd(user_data['消费金额'], user_data['会员等级'])
print(tukey.summary())

3. 分类变量 vs 分类变量

分析两个分类变量的关联性时,堆叠条形图和卡方检验是标准方法。

# 创建医疗数据示例
medical_data = pd.DataFrame({
    '治疗方案': np.random.choice(['A','B','C'], 500, p=[0.4,0.3,0.3]),
    '疗效': np.random.choice(['无效','改善','显著改善'], 500, 
                           p=[0.2,0.5,0.3])
})

# 交叉表
cross_tab = pd.crosstab(medical_data['治疗方案'], medical_data['疗效'], 
                       margins=True, margins_name="总计")
cross_tab_pct = cross_tab.div(cross_tab['总计'], axis=0) * 100

# 堆叠条形图
cross_tab_pct.iloc[:-1,:-1].plot(kind='bar', stacked=True, 
                                colormap='RdYlGn', figsize=(10,6))
plt.title('不同治疗方案疗效对比(%)', pad=15)
plt.ylabel('百分比')
plt.legend(bbox_to_anchor=(1.05,1))

# 卡方检验
chi2, p, dof, expected = stats.chi2_contingency(cross_tab.iloc[:-1,:-1])
print(f"卡方检验: χ² = {chi2:.2f}, p = {p:.4f}")

# 计算Cramer's V
n = cross_tab.iloc[-1,-1]
phi_corr = np.sqrt(chi2/(n*(min(cross_tab.shape)-1)))
print(f"Cramer's V = {phi_corr:.3f}")

4. 有序分类变量分析

当处理有序分类变量时,需要特殊的相关性度量方法。

# 创建客户满意度数据
survey_data = pd.DataFrame({
    '服务评分': np.random.choice(['差','中','良','优'], 300,
                              p=[0.1,0.3,0.4,0.2]),
    '回购意愿': np.random.choice(['低','中','高'], 300,
                             p=[0.2,0.5,0.3])
})

# 有序变量编码
rating_order = ['差','中','良','优']
buy_order = ['低','中','高']
survey_data['服务评分'] = pd.Categorical(survey_data['服务评分'], 
                                      categories=rating_order, ordered=True)
survey_data['回购意愿'] = pd.Categorical(survey_data['回购意愿'], 
                                     categories=buy_order, ordered=True)

# 热力图展示频率
pivot_table = survey_data.groupby(['服务评分','回购意愿']).size().unstack()
plt.figure(figsize=(8,6))
sns.heatmap(pivot_table, annot=True, fmt='d', cmap='YlGnBu', 
            cbar_kws={'label': '频数'})
plt.title('服务评分与回购意愿关联', pad=15)

# Kendall's tau-b检验
tau_b, p_value = stats.kendalltau(survey_data['服务评分'].cat.codes,
                                 survey_data['回购意愿'].cat.codes)
print(f"Kendall's tau-b = {tau_b:.3f}, p = {p_value:.4f}")

5. 混合类型变量分析

实际项目中常需要分析混合类型变量的关系,如连续变量与有序分类变量的关联。

# 员工绩效数据
employee_data = pd.DataFrame({
    '培训时长': np.random.normal(20, 5, 200),
    '绩效评级': pd.Categorical(
        np.random.choice(['C','B','A'], 200, p=[0.3,0.5,0.2]),
        categories=['C','B','A'], ordered=True)
})

# 分组箱线图
plt.figure(figsize=(10,6))
sns.boxplot(data=employee_data, x='绩效评级', y='培训时长',
           palette='coolwarm', width=0.5)
sns.swarmplot(data=employee_data, x='绩效评级', y='培训时长',
             color='black', alpha=0.4, size=3)
plt.title('不同绩效员工的培训时长分布', pad=15)

# Jonckheere-Terpstra趋势检验
from scipy.stats import kruskal
groups = [group['培训时长'].values 
          for _, group in employee_data.groupby('绩效评级')]
jt_stat, p_value = stats.kruskal(*groups)
print(f"Jonckheere-Terpstra近似检验: p = {p_value:.4f}")

高级可视化技巧

提升相关性分析呈现效果的专业可视化方法:

# 组合图表示例
fig, axes = plt.subplots(2, 2, figsize=(12,10))

# 1. 带边际分布的散点图
sns.scatterplot(data=data, x='广告投入', y='销售额', ax=axes[0,0])
sns.histplot(data=data, x='广告投入', kde=True, ax=axes[0,1], color='skyblue')
sns.histplot(data=data, y='销售额', kde=True, ax=axes[1,0], color='salmon')
axes[1,1].axis('off')

# 2. 分面网格图
grid = sns.FacetGrid(user_data, col='会员等级', height=4, aspect=1.2)
grid.map(sns.histplot, '消费金额', kde=True, bins=15)

# 3. 相关系数矩阵热力图
corr_matrix = data.corr()
mask = np.triu(np.ones_like(corr_matrix, dtype=bool))
sns.heatmap(corr_matrix, mask=mask, annot=True, cmap='coolwarm', 
            center=0, fmt='.2f', ax=axes[1,1])
axes[1,1].set_title('变量间相关系数矩阵', pad=10)

实战应用建议

  1. 数据预处理 :分析前确保处理缺失值(如插补或删除)和异常值(如Winsorize处理)

    # Winsorize处理示例
    from scipy.stats.mstats import winsorize
    data['销售额'] = winsorize(data['销售额'], limits=[0.05, 0.05])
    
  2. 多重检验校正 :当进行多次相关性检验时,应用Benjamini-Hochberg等方法控制错误发现率

    from statsmodels.stats.multitest import multipletests
    pvals = [0.01, 0.03, 0.05, 0.2]
    _, adj_p, _, _ = multipletests(pvals, method='fdr_bh')
    print(f"校正后p值: {adj_p}")
    
  3. 效应量解读 :除了统计显著性,还应报告相关系数大小等效应量指标

    相关系数范围 解释力度
    0.00-0.10 可忽略
    0.10-0.30 弱相关
    0.30-0.50 中等相关
    >0.50 强相关
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐