← 返回首页
🔍

数据分析实战:EDA流程、统计分析与数据洞察

📂 python ⏱ 4 min 663 words

数据分析实战:EDA流程、统计分析与数据洞察

探索性数据分析(EDA)是数据分析的第一步,通过可视化和统计方法理解数据的特征、发现模式和异常。本文将介绍完整的EDA流程和实用的统计分析方法。

EDA完整流程

一个标准的EDA流程包括以下步骤:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# 步骤1:加载数据
def load_data():
    np.random.seed(42)
    n = 500
    return pd.DataFrame({
        '年龄': np.random.normal(35, 10, n).astype(int).clip(18, 65),
        '收入': np.random.lognormal(10.5, 0.5, n).astype(int),
        '教育': np.random.choice(['高中', '本科', '硕士', '博士'], n, p=[0.2, 0.5, 0.25, 0.05]),
        '城市': np.random.choice(['北京', '上海', '广州', '深圳'], n),
        '满意度': np.random.randint(1, 11, n),
        '购买': np.random.choice([0, 1], n, p=[0.6, 0.4])
    })

df = load_data()

# 步骤2:数据概览
print("数据形状:", df.shape)
print("\n前5行:")
print(df.head())
print("\n数据类型:")
print(df.dtypes)
print("\n基本统计:")
print(df.describe())

# 步骤3:缺失值分析
print("\n缺失值:")
print(df.isnull().sum())
print(f"缺失比例: {df.isnull().sum().sum() / df.size * 100:.2f}%")

# 步骤4:异常值检测
Q1 = df['收入'].quantile(0.25)
Q3 = df['收入'].quantile(0.75)
IQR = Q3 - Q1
outliers = df[(df['收入'] < Q1 - 1.5 * IQR) | (df['收入'] > Q3 + 1.5 * IQR)]
print(f"\n收入异常值: {len(outliers)}条")

数据分布分析

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 数值变量分布
fig, axes = plt.subplots(2, 3, figsize=(15, 10))

# 年龄分布
axes[0, 0].hist(df['年龄'], bins=30, edgecolor='black', alpha=0.7)
axes[0, 0].set_title('年龄分布')
axes[0, 0].set_xlabel('年龄')

# 收入分布(对数正态)
axes[0, 1].hist(np.log1p(df['收入']), bins=30, edgecolor='black', alpha=0.7, color='orange')
axes[0, 1].set_title('收入分布(对数)')

# 满意度分布
df['满意度'].value_counts().sort_index().plot(kind='bar', ax=axes[0, 2], color='green')
axes[0, 2].set_title('满意度分布')

# 教育程度分布
df['教育'].value_counts().plot(kind='pie', ax=axes[1, 0], autopct='%1.1f%%')
axes[1, 0].set_title('教育程度分布')

# 城市分布
df['城市'].value_counts().plot(kind='bar', ax=axes[1, 1], color='coral')
axes[1, 1].set_title('城市分布')

# 收入箱线图
df.boxplot(column='收入', by='教育', ax=axes[1, 2])
axes[1, 2].set_title('各教育程度收入')

plt.tight_layout()
plt.show()

相关性分析

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

# 数值变量相关性
numeric_df = df['年龄', '收入', '满意度'](/notes/--)
corr_matrix = numeric_df.corr()

plt.figure(figsize=(8, 6))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', center=0, vmin=-1, vmax=1)
plt.title('数值变量相关性热力图')
plt.show()

# 与目标变量的关系
print("与购买行为的相关性:")
for col in ['年龄', '收入', '满意度']:
    corr = df[col].corr(df['购买'])
    print(f"{col}: {corr:.3f}")

# 交叉分析
cross_tab = pd.crosstab(df['教育'], df['购买'], normalize='index')
print("\n教育程度与购买率:")
print(cross_tab)

统计检验

from scipy import stats
import pandas as pd
import numpy as np

# 正态性检验
stat, p_value = stats.shapiro(df['年龄'].sample(100))
print(f"年龄正态性检验: p值={p_value:.4f}")

# T检验:比较两组均值
group_a = df[df['城市'] == '北京']['收入']
group_b = df[df['城市'] == '上海']['收入']
t_stat, p_value = stats.ttest_ind(group_a, group_b)
print(f"\n北京vs上海收入T检验: t={t_stat:.3f}, p={p_value:.3f}")

# 卡方检验:分类变量关联性
contingency = pd.crosstab(df['教育'], df['购买'])
chi2, p_value, dof, expected = stats.chi2_contingency(contingency)
print(f"\n教育与购买卡方检验: χ²={chi2:.3f}, p={p_value:.3f}")

# 方差分析(ANOVA)
groups = [df[df['城市'] == city]['收入'] for city in df['城市'].unique()]
f_stat, p_value = stats.f_oneway(*groups)
print(f"\n城市间收入方差分析: F={f_stat:.3f}, p={p_value:.3f}")

异常值处理

import pandas as pd
import numpy as np

def detect_outliers_iqr(series, threshold=1.5):
    Q1 = series.quantile(0.25)
    Q3 = series.quantile(0.75)
    IQR = Q3 - Q1
    lower = Q1 - threshold * IQR
    upper = Q3 + threshold * IQR
    return (series < lower) | (series > upper)

def detect_outliers_zscore(series, threshold=3):
    z_scores = np.abs(stats.zscore(series))
    return z_scores > threshold

# IQR方法
outliers_iqr = detect_outliers_iqr(df['收入'])
print(f"IQR检测异常值: {outliers_iqr.sum()}条")

# Z-score方法
from scipy import stats
outliers_zscore = detect_outliers_zscore(df['收入'])
print(f"Z-score检测异常值: {outliers_zscore.sum()}条")

# 处理异常值
df_clean = df.copy()
median_income = df_clean['收入'].median()
df_clean.loc[outliers_iqr, '收入'] = median_income
print(f"处理后收入范围: {df_clean['收入'].min()}-{df_clean['收入'].max()}")

数据洞察提取

import pandas as pd
import numpy as np

# 1. 关键指标计算
print("=== 关键业务指标 ===")
print(f"总样本数: {len(df)}")
print(f"购买转化率: {df['购买'].mean()*100:.1f}%")
print(f"平均年龄: {df['年龄'].mean():.1f}岁")
print(f"平均收入: {df['收入'].mean():.0f}元")

# 2. 高价值客户分析
print("\n=== 高价值客户特征 ===")
high_value = df[df['购买'] == 1]
low_value = df[df['购买'] == 0]

comparison = pd.DataFrame({
    '购买客户': [high_value['年龄'].mean(), high_value['收入'].mean(), high_value['满意度'].mean()],
    '未购买客户': [low_value['年龄'].mean(), low_value['收入'].mean(), low_value['满意度'].mean()]
}, index=['平均年龄', '平均收入', '平均满意度'])

print(comparison)

# 3. 转化率分析
print("\n=== 各维度转化率 ===")
for col in ['城市', '教育']:
    conversion = df.groupby(col)['购买'].mean() * 100
    print(f"\n{col}转化率:")
    print(conversion.sort_values(ascending=False))

# 4. 收入分层分析
df['收入层级'] = pd.cut(df['收入'], bins=[0, 5000, 10000, 20000, 100000],
                       labels=['低', '中', '高', '极高'])
print("\n=== 收入层级购买率 ===")
print(df.groupby('收入层级')['购买'].mean() * 100)

自动生成EDA报告

import pandas as pd
import numpy as np
from datetime import datetime

def generate_eda_report(df, target=None):
    """生成EDA报告"""
    report = []
    report.append(f"EDA报告 - {datetime.now().strftime('%Y-%m-%d %H:%M')}")
    report.append("=" * 50)
    
    # 数据概览
    report.append(f"\n数据集大小: {df.shape[0]}行 x {df.shape[1]}列")
    report.append(f"缺失值总数: {df.isnull().sum().sum()}")
    report.append(f"重复行数: {df.duplicated().sum()}")
    
    # 数值列统计
    numeric_cols = df.select_dtypes(include=[np.number]).columns
    if len(numeric_cols) > 0:
        report.append(f"\n数值变量({len(numeric_cols)}个):")
        for col in numeric_cols:
            report.append(f"  {col}: 均值={df[col].mean():.2f}, 标准差={df[col].std():.2f}")
    
    # 分类列统计
    cat_cols = df.select_dtypes(include=['object', 'category']).columns
    if len(cat_cols) > 0:
        report.append(f"\n分类变量({len(cat_cols)}个):")
        for col in cat_cols:
            report.append(f"  {col}: {df[col].nunique()}个类别, 最常见={df[col].mode()[0]}")
    
    # 目标变量分析
    if target and target in df.columns:
        report.append(f"\n目标变量 '{target}' 分布:")
        report.append(f"  {df[target].value_counts().to_dict()}")
    
    return "\n".join(report)

# 生成报告
print(generate_eda_report(df, target='购买'))

实战:客户流失分析

import pandas as pd
import numpy as np

# 模拟客户流失数据
np.random.seed(42)
n = 1000
churn_df = pd.DataFrame({
    '客户ID': range(1, n+1),
    '月消费': np.random.lognormal(6, 0.8, n).astype(int),
    '使用时长': np.random.exponential(24, n).astype(int).clip(1, 60),
    '投诉次数': np.random.poisson(1, n),
    '年龄': np.random.normal(35, 10, n).astype(int).clip(18, 65),
})

churn_df['是否流失'] = np.random.choice([0, 1], n, p=[0.8, 0.2])

# 流失原因分析
print("=== 流失客户特征 ===")
churned = churn_df[churn_df['是否流失'] == 1]
retained = churn_df[churn_df['是否流失'] == 0]

for col in ['月消费', '使用时长', '投诉次数']:
    print(f"{col}: 流失={churned[col].mean():.1f}, 保留={retained[col].mean():.1f}")

# 高风险客户识别
churn_df['流失风险'] = (
    (churn_df['月消费'] < churn_df['月消费'].quantile(0.25)).astype(int) +
    (churn_df['投诉次数'] > 1).astype(int) +
    (churn_df['使用时长'] < 6).astype(int)
)

high_risk = churn_df[churn_df['流失风险'] >= 2]
print(f"\n高风险客户: {len(high_risk)}人 ({len(high_risk)/n*100:.1f}%)")

总结

EDA是数据分析的核心技能。通过系统地探索数据,我们可以发现模式、识别问题、提取洞察。关键原则:先理解数据,再做分析;多用可视化,少用假设;关注业务问题,而非技术细节。