查看全课大纲(第 6 / 35 节)

工具应用:《泰坦尼克》分析报告

约 13 分钟

小象实战讲义 · 特征工程精讲与实践

在上一节我们了解了数据探索的基本概念和重要性。本节我们将聚焦于一个强大的自动化数据探索工具——pandas_profiling,并通过经典的泰坦尼克数据集来演示如何快速生成一份详尽的数据分析报告。这份报告将帮助我们高效地理解数据全貌,识别潜在问题,为后续的特征工程工作奠定坚实基础。

💡 核心导读

  • 自动化数据探索:掌握使用 pandas_profiling 一键生成全面数据报告的方法。
  • 报告解读实战:学习如何阅读和理解报告中的关键模块,包括数据集概览、变量分析、相关性矩阵和缺失值统计。
  • 数据洞察提炼:从泰坦尼克数据报告的具体分析中,学习提取对建模有指导意义的业务洞察(如舱位等级与生存率的关系)。
  • 工具价值认知:理解自动化探索工具在特征工程流程中的定位,它如何替代大量手动统计分析,提升工作效率。

使用 pandas_profiling 生成报告

pandas_profiling 是一个能够自动从 pandas DataFrame 生成交互式数据报告的库。它极大地简化了数据探索的初期工作,将描述性统计、分布可视化、相关性分析和缺失值检测等多个步骤整合在一个 HTML 报告中。

原课程使用 pandas_profiling 库的 ProfileReport(df) 一行代码即可生成完整的交互式 HTML 报告(该库后续已更名为 ydata_profiling)。讲义按依赖纪律以 pandas 基础操作等价呈现报告背后的核心统计逻辑:

import pandas as pd
import numpy as np

# 构造一个微型泰坦尼克数据集样例(用于演示)
data = {
    'PassengerId': [1, 2, 3, 4, 5, 6, 7, 8],
    'Survived': [0, 1, 1, 1, 0, 0, 0, 1],
    'Pclass': [3, 1, 3, 1, 3, 3, 2, 3],
    'Name': ['Braund, Mr. Owen Harris', 'Cumings, Mrs. John Bradley', 'Heikkinen, Miss. Laina', 'Futrelle, Mrs. Jacques Heath', 'Allen, Mr. William Henry', 'Moran, Mr. James', 'McCarthy, Mr. Timothy J', 'Palsson, Master. Gosta Leonard'],
    'Sex': ['male', 'female', 'female', 'female', 'male', 'male', 'male', 'male'],
    'Age': [22.0, 38.0, 26.0, 35.0, 35.0, np.nan, 54.0, 2.0],
    'SibSp': [1, 1, 0, 1, 0, 0, 0, 3],
    'Parch': [0, 0, 0, 0, 0, 0, 0, 1],
    'Ticket': ['A/5 21171', 'PC 17599', 'STON/O2. 3101282', '113803', '373450', '330877', '17463', '349909'],
    'Fare': [7.25, 71.28, 7.92, 53.1, 8.05, 8.46, 51.86, 21.07],
    'Cabin': [None, 'C85', None, 'C123', None, None, 'E46', None],
    'Embarked': ['S', 'C', 'S', 'S', 'S', 'Q', 'S', 'S']
}
df = pd.DataFrame(data)

# 基础探索(pandas_profiling 报告的底层就是这些统计)
print("数据形状:", df.shape)
print("\n前5行预览:")
print(df.head())
print("\n各字段缺失值数量:")
print(df.isnull().sum()[df.isnull().sum() > 0])
数据形状: (8, 12)

前5行预览:
   PassengerId  Survived  Pclass  ...   Fare Cabin  Embarked
0            1         0       3  ...   7.25   NaN         S
1            2         1       1  ...  71.28   C85         C
2            3         1       3  ...   7.92   NaN         S
3            4         1       1  ...  53.10  C123         S
4            5         0       3  ...   8.05   NaN         S

[5 rows x 12 columns]

各字段缺失值数量:
Age      1
Cabin    5
dtype: int64

在原课程的实际操作中,ProfileReport(df) 会在几秒钟内把这类统计扩展成一份包含分布图、相关性热力图与缺失值可视化的交互式报告并保存为 HTML 文件。接下来,我们以原课程中使用的完整泰坦尼克数据集报告为例,解读其中的关键部分。

解读泰坦尼克数据集分析报告

生成的报告通常包含以下几个核心部分:数据集概览(Overview)、变量分析(Variables)、交互散点(Interactions)、相关性分析(Correlations)、缺失值分析(Missing values) 和 样本数据(Sample)。我们逐一解读。

1. 数据集概览(Overview)

报告开头会对整个数据集做一个“体检”,给出宏观画像。

import pandas as pd
import numpy as np

# 微型泰坦尼克数据(与本节首块一致)
data = {
    'PassengerId': [1, 2, 3, 4, 5, 6, 7, 8],
    'Survived': [0, 1, 1, 1, 0, 0, 0, 1],
    'Pclass': [3, 1, 3, 1, 3, 3, 2, 3],
    'Name': ['Braund', 'Cumings', 'Heikkinen', 'Futrelle', 'Allen', 'Moran', 'McCarthy', 'Palsson'],
    'Sex': ['male', 'female', 'female', 'female', 'male', 'male', 'male', 'male'],
    'Age': [22.0, 38.0, 26.0, 35.0, 35.0, np.nan, 54.0, 2.0],
    'SibSp': [1, 1, 0, 1, 0, 0, 0, 3],
    'Parch': [0, 0, 0, 0, 0, 0, 0, 1],
    'Ticket': ['A/5 21171', 'PC 17599', 'STON/O2. 3101282', '113803', '373450', '330877', '17463', '349909'],
    'Fare': [7.25, 71.28, 7.92, 53.1, 8.05, 8.46, 51.86, 21.07],
    'Cabin': [None, 'C85', None, 'C123', None, None, 'E46', None],
    'Embarked': ['S', 'C', 'S', 'S', 'S', 'Q', 'S', 'S']
}

import pandas as pd

# 为了演示概览信息,我们手动计算微型样例的类似统计
df_overview = pd.DataFrame(data)
num_variables = df_overview.shape[1]
num_observations = df_overview.shape[0]
total_missing_cells = df_overview.isnull().sum().sum()
missing_percentage = (total_missing_cells / (num_variables * num_observations) * 100).round(1)

print("数据集概览 (基于微型样例):")
print(f"变量数 (Number of variables): {num_variables}")
print(f"样本数 (Number of observations): {num_observations}")
print(f"缺失单元格总数 (Total missing cells): {total_missing_cells}")
print(f"缺失比例 (Missing cells, %): {missing_percentage}%")
# 区分变量类型
numeric_vars = df_overview.select_dtypes(include=['number']).columns.tolist()
categorical_vars = df_overview.select_dtypes(include=['object', 'category']).columns.tolist()
bool_vars = df_overview.select_dtypes(include=['bool']).columns.tolist()
print(f"\n数值型变量: {numeric_vars}")
print(f"类别型变量: {categorical_vars}")
print(f"布尔型变量: {bool_vars}")
数据集概览 (基于微型样例):
变量数 (Number of variables): 12
样本数 (Number of observations): 8
缺失单元格总数 (Total missing cells): 6
缺失比例 (Missing cells, %): 6.2%

数值型变量: ['PassengerId', 'Survived', 'Pclass', 'Age', 'SibSp', 'Parch', 'Fare']
类别型变量: ['Name', 'Sex', 'Ticket', 'Cabin', 'Embarked']
布尔型变量: []

在完整的泰坦尼克报告(891个样本)中,概览显示:共有12个变量(字段),891条样本,缺失单元格总数为866个(缺失比例约8.1%),并识别出有6个类别型字段、5个数值型字段和1个布尔型字段(Survived)。这让我们在几秒钟内就对数据规模、完整度和结构有了清晰认识。

2. 变量分析(Variables)

报告会对每一个字段进行详细分析。对于类别型变量(如 Survived, Pclass, Sex),它会展示取值分布、计数和百分比,并以饼图或柱状图可视化。

import pandas as pd
# 分析 Survived(生存状态)字段的分布
survived_counts = pd.Series([0, 1, 1, 1, 0, 0, 0, 1]).value_counts()
survived_percentage = (survived_counts / len([0,1,1,1,0,0,0,1]) * 100).round(1)

print("Survived 字段分析 (微型样例):")
print("取值 | 计数 | 百分比%")
print("-" * 25)
for val in sorted(survived_counts.index):
    print(f"{val:^6} | {survived_counts[val]:^4} | {survived_percentage[val]:^6}")
Survived 字段分析 (微型样例):
取值 | 计数 | 百分比%
-------------------------
  0    |  4   |  50.0 
  1    |  4   |  50.0 

在完整报告中,Survived=0(遇难)有549人,占61.6%;Survived=1(获救)有342人,占38.4%。对于 Pclass(舱位等级),报告显示三等舱乘客最多(491人,占55.1%),一等舱和二等舱人数相近(各约20%)。这些分布信息对理解样本构成至关重要。

对于数值型变量(如 Age, Fare),报告会提供丰富的描述性统计量,并绘制直方图展示分布。

import pandas as pd
# 分析 Age(年龄)字段的描述性统计(处理缺失值后)
age_series = pd.Series([22.0, 38.0, 26.0, 35.0, 35.0, 54.0, 2.0]) # 移除了NaN
age_stats = age_series.describe(percentiles=[.05, .25, .5, .75, .95])
print("Age 字段描述性统计 (微型样例,已剔除NaN):")
print(age_stats.round(2))
print(f"\nAge 缺失值数量 (在原数据中): 1")
Age 字段描述性统计 (微型样例,已剔除NaN):
count     7.00
mean     30.29
std      16.09
min       2.00
5%        8.00
25%      24.00
50%      35.00
75%      36.50
95%      49.20
max      54.00
dtype: float64

Age 缺失值数量 (在原数据中): 1

完整报告中,Age 的统计显示:最小年龄0.42岁(可能是婴儿),中位数28岁,75分位数38岁(说明75%的乘客年龄≤38岁),95分位数56岁,最大年龄80岁。直方图清晰显示年龄集中分布在20-35岁区间。报告还会用红色高亮提示该字段存在缺失值(共缺失177个),这是我们后续特征预处理需要解决的重点问题。

3. 相关性分析(Correlations)

报告会计算数值变量之间的相关系数矩阵(默认使用皮尔逊相关系数),并以热力图形式展示。热力图使用发散色图(RdBu):深冷色(深蓝)表示强正相关、深暖色(深红)表示强负相关,颜色越浅(越接近白色)表示相关性越弱(接近 0)。

import pandas as pd
# 计算微型样例中数值变量的相关性矩阵
import numpy as np
# 重新构造包含数值型变量的DataFrame
df_corr = pd.DataFrame({
    'Pclass': [3, 1, 3, 1, 3, 3, 2, 3],
    'Age': [22.0, 38.0, 26.0, 35.0, 35.0, np.nan, 54.0, 2.0],
    'SibSp': [1, 1, 0, 1, 0, 0, 0, 3],
    'Parch': [0, 0, 0, 0, 0, 0, 0, 1],
    'Fare': [7.25, 71.28, 7.92, 53.1, 8.05, 8.46, 51.86, 21.07],
    'Survived': [0, 1, 1, 1, 0, 0, 0, 1]
})
# 计算相关性,并处理缺失值(对于演示,用均值填充Age)
df_corr_filled = df_corr.fillna(df_corr['Age'].mean())
corr_matrix = df_corr_filled.corr(method='pearson')
print("数值变量相关性矩阵 (皮尔逊相关系数,微型样例):")
print(corr_matrix.round(2))
数值变量相关性矩阵 (皮尔逊相关系数,微型样例):
          Pclass   Age  SibSp  Parch  Fare  Survived
Pclass      1.00 -0.51  -0.04   0.28 -0.94     -0.44
Age        -0.51  1.00  -0.75  -0.77  0.51     -0.36
SibSp      -0.04 -0.75   1.00   0.88  0.12      0.52
Parch       0.28 -0.77   0.88   1.00 -0.12      0.38
Fare       -0.94  0.51   0.12  -0.12  1.00      0.40
Survived   -0.44 -0.36   0.52   0.38  0.40      1.00

从完整报告的热力图中,我们可以发现一些有意义的模式:

  • Pclass 与 Fare 高度负相关(约-0.55):这符合常识,舱位等级数字越小(一等舱),票价越高。
  • Pclass 与 Survived 负相关:舱位等级数字越大(三等舱),生存率越低。这揭示了当时救援可能存在的社会经济地位差异,是一个强烈的预测信号。
  • Fare 与 Survived 正相关:票价越高,生存率也倾向于更高,这与舱位等级的发现一致。
  • SibSp(同代亲属数)与 Parch(上下代亲属数)正相关:家庭成员数量往往相关联。

这些相关性分析为我们后续的特征选择(例如剔除高度共线性的特征)和业务理解提供了直接依据。

4. 缺失值分析(Missing values)

报告会以柱状图形式清晰展示每个字段的缺失值数量,让我们一眼锁定问题字段。

import pandas as pd
import numpy as np

# 微型泰坦尼克数据(与本节首块一致)
data = {
    'PassengerId': [1, 2, 3, 4, 5, 6, 7, 8],
    'Survived': [0, 1, 1, 1, 0, 0, 0, 1],
    'Pclass': [3, 1, 3, 1, 3, 3, 2, 3],
    'Name': ['Braund', 'Cumings', 'Heikkinen', 'Futrelle', 'Allen', 'Moran', 'McCarthy', 'Palsson'],
    'Sex': ['male', 'female', 'female', 'female', 'male', 'male', 'male', 'male'],
    'Age': [22.0, 38.0, 26.0, 35.0, 35.0, np.nan, 54.0, 2.0],
    'SibSp': [1, 1, 0, 1, 0, 0, 0, 3],
    'Parch': [0, 0, 0, 0, 0, 0, 0, 1],
    'Ticket': ['A/5 21171', 'PC 17599', 'STON/O2. 3101282', '113803', '373450', '330877', '17463', '349909'],
    'Fare': [7.25, 71.28, 7.92, 53.1, 8.05, 8.46, 51.86, 21.07],
    'Cabin': [None, 'C85', None, 'C123', None, None, 'E46', None],
    'Embarked': ['S', 'C', 'S', 'S', 'S', 'Q', 'S', 'S']
}

import pandas as pd
# 统计微型样例中各字段的缺失值
missing_summary = pd.DataFrame(data).isnull().sum()
missing_percentage = (pd.DataFrame(data).isnull().sum() / len(pd.DataFrame(data)) * 100).round(1)
missing_df = pd.DataFrame({'缺失数量': missing_summary, '缺失百分比%': missing_percentage})
print("各字段缺失值统计 (微型样例):")
print(missing_df[missing_df['缺失数量'] > 0])
各字段缺失值统计 (微型样例):
       缺失数量  缺失百分比%
Age       1    12.5
Cabin     5    62.5

在完整报告中,缺失值分析显示:Cabin(客舱号)字段缺失最多(约77%),Age(年龄)缺失约20%,Embarked(登船港口)缺失2个。这提示我们,Cabin 字段信息极度不全,可能需要谨慎使用或构造衍生特征(如是否有客舱记录);Age 的缺失则需要采用填充策略。

报告的价值与在特征工程中的位置

通过 pandas_profiling 生成的报告,我们在几分钟内就完成了对泰坦尼克数据集的“初诊”。它帮助我们:

  1. 快速理解数据:掌握数据规模、类型和基本分布。
  2. 定位数据问题:清晰识别缺失字段、极端取值(如最小年龄仅0.42岁的婴儿)和长尾分布。
  3. 发现潜在模式:通过相关性分析揭示特征与目标变量(Survived)以及特征之间的关系。
  4. 指导后续工作:报告结论直接指引后续特征工程的方向,例如:
    • 对 Age 进行缺失值填充。
    • 考虑 Cabin 字段的可用性,或从中提取信息(如甲板层)。
    • 利用 Pclass 与 Survived 的强关系,该特征很可能被选中。
    • 根据 SibSp 和 Parch 构造“家庭规模”衍生特征。

在特征工程的完整流程中,数据探索是紧接在数据收集之后的第二步。这份自动化报告正是这一步的高效产出物,它为后续的特征预处理、构建与选择提供了数据层面的决策依据。

📝 动手练一练

  1. 概念辨析:pandas_profiling 报告中的“相关性矩阵”主要反映的是什么关系?它对于特征选择有什么指导意义?如果两个特征之间相关性极高(例如 >0.9),在建模时通常建议如何处理?
👉 点击查看参考答案

报告中的相关性矩阵(默认使用皮尔逊相关系数)主要反映的是数值型特征之间的线性相关程度。对于特征选择的指导意义在于:1)识别与目标变量强相关的特征,这些可能是重要的预测因子;2)识别特征之间的多重共线性。如果两个特征之间相关性极高(>0.9),通常意味着它们携带的信息高度冗余,同时保留可能会引入不必要的噪声并增加模型复杂度。一般的处理建议是:根据业务理解或通过特征重要性评估,剔除其中一个,或者使用主成分分析(PCA)等降维方法将它们合并为新的特征。

  1. 动手实践:参考本节微型样例代码,尝试为 Pclass(舱位等级)字段手动计算其取值分布(计数和百分比),并与 pandas_profiling 报告自动生成的结果进行对比理解。
👉 点击查看参考答案
import pandas as pd
# 使用微型样例数据
pclass_data = [3, 1, 3, 1, 3, 3, 2, 3]
pclass_series = pd.Series(pclass_data)
pclass_counts = pclass_series.value_counts().sort_index()
pclass_percentage = (pclass_counts / len(pclass_series) * 100).round(1)

print("Pclass 字段取值分布 (手动计算):")
print("等级 | 计数 | 百分比%")
print("-" * 25)
for pclass in pclass_counts.index:
    print(f"{pclass:^4} | {pclass_counts[pclass]:^4} | {pclass_percentage[pclass]:^6}")
Pclass 字段取值分布 (手动计算):
等级 | 计数 | 百分比%
-------------------------
 1   |  2   |  25.0 
 2   |  1   |  12.5 
 3   |  5   |  62.5 

手动计算显示,在8个样例乘客中,一等舱2人(25%),二等舱1人(12.5%),三等舱5人(62.5%)。pandas_profiling 报告会自动完成类似计算,并以更直观的表格和饼图呈现。通过手动计算,可以加深对工具背后统计逻辑的理解。

本章小结

本节我们深入学习了如何利用 pandas_profiling 这一自动化工具进行高效的数据探索。我们以泰坦尼克数据集为例,完整走过了生成报告、解读报告并从中提炼特征工程洞察的全过程。记住,一份好的数据报告是后续所有特征处理工作的蓝图。

📋 行动清单

  • 运行一次 pandas_profiling:在你自己的一个数据集(或课程提供的链家数据)上运行代码,生成并浏览完整的 HTML 报告。
  • 练习报告解读:针对生成的报告,尝试回答:数据集中缺失最严重的字段是哪个?哪个数值特征与目标变量的相关性最强?数据中是否存在明显的类别不平衡?
  • 制定预处理计划:根据报告发现的问题(如缺失值、异常分布),在笔记本上简要列出你接下来准备进行的特征预处理步骤(例如:对字段X采用中位数填充,对字段Y进行分箱处理)。

—— 小象教研组