用Pandas完成完整数据分析:从数据清洗到可视化(泰坦尼克号数据集实操)
在数据分析领域,Pandas是Python生态中最核心的数据处理工具,凭借简洁的语法、高效的批量处理能力,以及与可视化库的无缝衔接,成为结构化数据分析的首选工具。本文将以经典的泰坦尼克号生存数据集为例,带大家走完从环境准备、数据加载、探索性分析,到核心的数据清洗、特征工程、分组分析,再到可视化呈现的完整流程,所有代码可直接复制运行,同时拆解实操思路与常见避坑点,帮助新手快速掌握Pandas数据分析的核心技巧。
一、前置准备:安装核心依赖库
本次完整流程需用到4个核心库,各司其职、协同工作,首次使用需执行安装命令,推荐使用清华镜像源提升安装速度:
pip install pandas numpy matplotlib seaborn scipy -i https://pypi.tuna.tsinghua.edu.cn/simple各库核心作用说明:
- Pandas:核心工具,负责数据加载、清洗、筛选、分组聚合等全流程数据处理;
- NumPy:辅助数值计算,用于缺失值填充、异常值检测与修正等;
- Matplotlib/Seaborn:数据可视化工具,Seaborn基于Matplotlib封装,绘图更美观、适配Pandas数据结构,新手友好;
- Scipy(可选):辅助进行统计检验,验证特征与目标变量的相关性是否显著。
二、数据分析全流程框架
完整的Pandas数据分析流程遵循“数据加载→探索性分析→数据清洗→特征工程→分析建模→可视化呈现”的逻辑,其中数据清洗是最核心、最耗时的环节(实际工作中占比60%以上),直接决定后续分析结果的可靠性,也是新手最容易忽略的关键步骤。本次实操选用Seaborn内置的泰坦尼克号数据集,该数据集包含891名乘客的基本信息(年龄、性别、舱位等)与生存状态,存在缺失值、分类变量等典型数据问题,贴近实际业务场景,无需手动下载,可直接调用,非常适合入门练习。
三、全环节实操代码与详细讲解
步骤1:导入库+加载数据
首先导入所有核心库,并配置可视化环境(解决Matplotlib/Seaborn中文乱码、负号显示异常的问题),随后加载数据集并明确字段含义,为后续分析奠定基础。
# 导入所有核心库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 全局可视化设置:解决中文乱码、负号显示问题,统一绘图风格
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统用黑体,Mac系统替换为['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
sns.set_style('whitegrid') # 统一设置为白色网格风格,提升图表美观度
# 加载Seaborn内置泰坦尼克数据集,转为Pandas的DataFrame(数据分析核心数据结构,二维表格形式)
df = sns.load_dataset('titanic')数据集字段含义(必看,避免分析无方向):
字段 | 含义 | 字段 | 含义 |
|---|---|---|---|
survived | 生存标签(0=死亡,1=生存) | age | 年龄 |
pclass | 客舱等级(1=一等,2=二等,3=三等) | sibsp | 兄弟姐妹/配偶同行数 |
sex | 性别 | parch | 父母/子女同行数 |
fare | 船票价格 | embarked | 登船港口(C=瑟堡,Q=昆斯敦,S=南安普顿) |
cabin | 船舱号 | who | 人群分类(man/woman/child) |
步骤2:探索性数据分析(EDA)
探索性数据分析的核心目的是快速了解数据全貌,发现潜在问题(如缺失值、重复值、异常值、数据类型错误等),为后续数据清洗明确方向。Pandas提供了5个核心函数,可完成80%的探索工作,新手必须熟练掌握:
# 1. 查看前5行数据(了解字段内容、数据格式),tail(5)可查看后5行
print("数据前5行:")
print(df.head())
# 2. 查看数据基本信息:行/列数、字段类型、非空值数量(重点关注缺失值)
print("\n数据基本信息:")
print(df.info())
# 3. 查看数值型字段的统计特征:均值、中位数、四分位数、最值、标准差(辅助发现异常值)
print("\n数值型字段统计描述:")
print(df.describe())
# 4. 查看分类变量的分布(value_counts):统计各类别数量及占比
print("\n生存标签分布(0=死亡,1=生存):")
print(df['survived'].value_counts())
print("\n客舱等级分布(含占比):")
print(df['pclass'].value_counts(normalize=True).round(3)) # normalize=True显示占比,round(3)保留3位小数
# 5. 查看数值型字段间的相关性:corr(),取值范围[-1,1],绝对值越大相关性越强
print("\n数值型字段相关性矩阵(重点看与生存标签的相关性):")
print(df.corr(numeric_only=True)['survived'].sort_values(ascending=False))探索结果关键总结(直接决定后续清洗重点):
- 数据规模:共891行(乘客)、15列(字段),经验证无重复行(duplicated().sum()结果为0);
- 缺失值问题:存在4个字段有缺失值——age(年龄,177个缺失)、embarked(登船口,2个缺失)、deck(船舱号,688个缺失)、embark_town(登船城市,2个缺失);
- 相关性线索:生存标签(survived)与客舱等级(pclass)负相关(-0.34)、与船票价格(fare)正相关(0.26),与人群分类(who)强相关,为后续分析提供方向;
- 数据类型:分类变量(如sex、embarked)为object类型,部分数值型字段(如pclass、survived)实际为分类含义,后续可优化类型以节省内存;
- 异常值线索:船票价格(fare)最小值为0,可能存在异常,需后续进一步验证。
步骤3:数据清洗(核心环节)
数据清洗的核心原则是“保留有效数据、修正错误数据、删除无用数据”,针对探索性分析发现的问题,逐一处理缺失值、重复值、异常值,同时删除冗余字段,确保数据干净可用。
3.1 处理重复值
重复行会导致分析结果失真,需先检测再删除,本次数据集无重复行,仅演示通用方法:
# 检测重复行:duplicated()返回每行是否重复的布尔值,sum()统计重复行数
duplicate_num = df.duplicated().sum()
print(f"重复行数量:{duplicate_num}") # 本次结果:0,无需删除
# 若有重复行,执行删除操作(inplace=True表示直接修改原DataFrame)
# df = df.drop_duplicates(inplace=True)3.2 处理缺失值
缺失值处理需结合“缺失率+字段含义”选择合适方法,避免无脑删除或填充,常用方法及适用场景如下:
处理方法 | 适用场景 | 本次实操示例 |
|---|---|---|
中位数/均值填充 | 数值型字段、缺失率低(<20%) | age(年龄)用中位数填充(抗异常值能力强于均值) |
众数填充 | 分类变量、缺失率低(<5%) | embarked(登船口)用众数填充 |
直接删除 | 缺失率极高(>70%)/无业务意义 | deck(船舱号)缺失率77%,直接删除 |
业务逻辑填充 | 字段间有明确业务关联 | 儿童年龄可结合who字段填充(本次简化处理) |
# 1. 删除缺失率极高的字段+冗余字段
# deck:缺失率77%,无实际分析价值;embark_town与embarked重复,alive与survived重复
df = df.drop(columns=['deck', 'embark_town', 'alive'])
# 2. 数值型字段:age用中位数填充
df['age'] = df['age'].fillna(df['age'].median())
# 3. 分类字段:embarked用众数填充(mode()[0]取第一个众数)
df['embarked'] = df['embarked'].fillna(df['embarked'].mode()[0])
# 验证缺失值处理结果:所有字段缺失值应为0
print("清洗后缺失值统计:")
print(df.isnull().sum())3.3 处理异常值
异常值是指数值型字段中明显偏离正常范围的值(如年龄100岁、船票价格为负数),常用检测方法为箱线图法(IQR)(直观、通用)和3σ原则(适用于正态分布数据)。处理原则:轻微异常(如高端舱位的高票价)保留,极端异常(如年龄200岁)修正或删除,避免丢失有效数据。本次以age(年龄)和fare(船票价格)为例,演示异常值检测与处理:
# 定义箱线图检测异常值的函数(可复用)
def detect_outliers(df, col):
"""
检测数值型字段的异常值
:param df: 数据集(DataFrame)
:param col: 需检测的数值型字段名
:return: 异常值数量、异常值索引
"""
q1 = df[col].quantile(0.25) # 下四分位数(25%分位数)
q3 = df[col].quantile(0.75) # 上四分位数(75%分位数)
iqr = q3 - q1 # 四分位距
lower_bound = q1 - 1.5 * iqr # 异常值下界
upper_bound = q3 + 1.5 * iqr # 异常值上界
outliers = df[(df[col] < lower_bound) | (df[col] > upper_bound)]
return len(outliers), outliers.index
# 检测age和fare的异常值
age_outliers_num, _ = detect_outliers(df, 'age')
fare_outliers_num, _ = detect_outliers(df, 'fare')
print(f"年龄异常值数量:{age_outliers_num}") # 结果:66(多为低龄/高龄,合理,保留)
print(f"票价异常值数量:{fare_outliers_num}") # 结果:116(高端舱位票价高,合理,保留)
# 若有极端异常值(如年龄200岁),用上下界替换(示例代码)
# df.loc[df[col] > upper_bound, col] = upper_bound
# df.loc[df[col] < lower_bound, col] = lower_bound3.4 数据类型修正(可选,优化性能)
本次数据集字段类型无明显错误,但分类变量(如sex、embarked、pclass)若保持object/int类型,会占用较多内存。将其转为Pandas专属的category类型,可大幅节省内存、提升后续运算速度:
# 将分类变量转为category类型
df['sex'] = df['sex'].astype('category')
df['embarked'] = df['embarked'].astype('category')
df['pclass'] = df['pclass'].astype('category')
df['survived'] = df['survived'].astype('category')
# 验证数据类型修正结果
print("\n数据类型修正后:")
print(df.dtypes)步骤4:特征工程(进阶,提升分析深度)
特征工程的核心目的是基于原始字段,构建新的、有业务意义的特征,从而提升分析深度。本次结合泰坦尼克号数据集的业务场景,构建2个常用特征,演示特征工程的基础思路:
# 1. 构建家庭规模特征(family_size):同行人数+自身(sibsp+parch+1)
df['family_size'] = df['sibsp'] + df['parch'] + 1
# 2. 构建年龄分组特征(age_group):将连续年龄转为分类变量,方便分组分析
df['age_group'] = pd.cut(
df['age'],
bins=[0, 12, 25, 60, 100], # 分箱边界:0-12(儿童)、13-25(青年)、26-60(中年)、61-100(老年)
labels=['儿童', '青年', '中年', '老年'], # 分箱标签
right=False # 左闭右开区间(如[0,12)表示0≤age<12)
)
# 查看新特征的分布情况,验证特征合理性
print("年龄分组分布:")
print(df['age_group'].value_counts())
print("\n家庭规模分布:")
print(df['family_size'].value_counts())步骤5:探索性分析(基于清洗后的数据)
数据清洗与特征工程完成后,即可通过Pandas的分组聚合(groupby)功能,挖掘数据规律,核心是回答业务问题:“哪些因素影响泰坦尼克号乘客的生存概率?”
# 分析1:不同客舱等级的生存率(统计总人数、生存人数、生存率)
pclass_survive = df.groupby('pclass')['survived'].agg(['count', 'sum', 'mean'])
pclass_survive.columns = ['总人数', '生存人数', '生存率']
print("\n不同客舱等级的生存率:")
print(pclass_survive.round(3)) # round(3)保留3位小数
# 分析2:不同性别的生存率
sex_survive = df.groupby('sex')['survived'].agg(['count', 'sum', 'mean'])
sex_survive.columns = ['总人数', '生存人数', '生存率']
print("\n不同性别的生存率:")
print(sex_survive.round(3))
# 分析3:不同年龄分组的生存率
age_group_survive = df.groupby('age_group')['survived'].agg(['count', 'sum', 'mean'])
age_group_survive.columns = ['总人数', '生存人数', '生存率']
print("\n不同年龄分组的生存率:")
print(age_group_survive.round(3))
# 分析4:客舱等级+性别 联合生存率(多维度分组,更贴近实际场景)
pclass_sex_survive = df.groupby(['pclass', 'sex'])['survived'].mean().unstack() # unstack()行转列,提升可读性
print("\n客舱等级+性别联合生存率:")
print(pclass_sex_survive.round(3))
# 分析5:家庭规模与生存率的关系
family_survive = df.groupby('family_size')['survived'].mean()
print("\n家庭规模与生存率:")
print(family_survive.round(3))核心分析结论(提炼关键规律):
- 客舱等级:等级越高,生存率越高(一等舱62.9% > 二等舱47.3% > 三等舱24.2%),体现了当时的阶级差异;
- 性别:女性生存率(74.2%)远高于男性(18.9%),符合泰坦尼克号“女士优先”的救援原则;
- 年龄:儿童生存率最高(59.0%),老年生存率最低(34.7%),符合“优先救助老弱妇孺”的普遍逻辑;
- 联合因素:一等舱女性生存率接近100%(96.8%),三等舱男性生存率仅13.7%,是影响生存的最核心组合因素;
- 家庭规模:小家庭(2-3人)生存率更高,单身或大家庭(6人以上)因分散、照顾难度大,生存率偏低。
步骤6:数据可视化(直观呈现分析结果)
“一图胜千言”,可视化是数据分析结果呈现的核心方式。结合Matplotlib和Seaborn,针对上述分析结果,选择合适的图表类型,实现“单维度分布、多维度关联、相关性可视化”,所有图表均可保存为高清图片,用于报告呈现。可视化核心原则:图表类型匹配数据关系(分类对比用柱状图、分布用直方图/箱线图、相关性用热力图),标题、坐标轴标签、图例清晰,避免信息过载。
6.1 单维度可视化:生存人数/率分布
# 图1:生存与死亡人数柱状图(基础可视化,展示整体生存情况)
plt.figure(figsize=(8, 5)) # 设置画布大小(宽×高)
sns.countplot(x='survived', data=df, palette=['#E74C3C', '#2ECC71']) # palette设置颜色(红色=死亡,绿色=生存)
plt.title('泰坦尼克号乘客生存/死亡人数分布', fontsize=14)
plt.xlabel('生存标签(0=死亡,1=生存)', fontsize=12)
plt.ylabel('人数', fontsize=12)
plt.xticks([0, 1], ['死亡', '生存']) # 替换x轴标签,更易懂
# 为柱子添加数值标签,提升可读性
for p in plt.gca().patches:
plt.gca().text(p.get_x() + p.get_width()/2, p.get_height() + 10, f'{int(p.get_height())}',
ha='center', va='bottom', fontsize=11)
plt.tight_layout() # 自动调整布局,避免标签重叠
plt.savefig('生存人数分布.png', dpi=300) # 保存高清图片(dpi=300,适合报告)
plt.show() # 显示图表
# 图2:不同客舱等级的生存率柱状图(百分比展示)
plt.figure(figsize=(8, 5))
sns.barplot(x='pclass', y='survived', data=df, palette=['#3498DB', '#9B59B6', '#E67E22'])
plt.title('不同客舱等级的生存率', fontsize=14)
plt.xlabel('客舱等级(1=一等,2=二等,3=三等)', fontsize=12)
plt.ylabel('生存率', fontsize=12)
plt.ylim(0, 1) # y轴范围设为0-1,符合概率取值范围
# 添加百分比标签
for p in plt.gca().patches:
plt.gca().text(p.get_x() + p.get_width()/2, p.get_height() + 0.02,
f'{p.get_height():.1%}', ha='center', va='bottom', fontsize=11)
plt.tight_layout()
plt.savefig('客舱等级生存率.png', dpi=300)
plt.show()6.2 多维度可视化:联合因素对生存率的影响
# 图3:客舱等级+性别 联合生存率分组柱状图(核心可视化,展示多因素影响)
plt.figure(figsize=(10, 6))
sns.barplot(x='pclass', y='survived', hue='sex', data=df,
palette={'male':'#3498DB', 'female':'#E74C3C'})
plt.title('不同客舱等级+性别的生存率', fontsize=14)
plt.xlabel('客舱等级', fontsize=12)
plt.ylabel('生存率', fontsize=12)
plt.ylim(0, 1)
plt.legend(title='性别', labels=['男性', '女性']) # 修正图例标签,更易懂
# 添加百分比标签
for p in plt.gca().patches:
plt.gca().text(p.get_x() + p.get_width()/2, p.get_height() + 0.02,
f'{p.get_height():.1%}', ha='center', va='bottom', fontsize=10)
plt.tight_layout()
plt.savefig('客舱等级+性别生存率.png', dpi=300)
plt.show()
# 图4:不同年龄分组的生存率柱状图
plt.figure(figsize=(10, 6))
sns.barplot(x='age_group', y='survived', data=df, palette=['#F1C40F', '#27AE60', '#8E44AD', '#E67E22'])
plt.title('不同年龄分组的生存率', fontsize=14)
plt.xlabel('年龄分组', fontsize=12)
plt.ylabel('生存率', fontsize=12)
plt.ylim(0, 1)
for p in plt.gca().patches:
plt.gca().text(p.get_x() + p.get_width()/2, p.get_height() + 0.02,
f'{p.get_height():.1%}', ha='center', va='bottom', fontsize=11)
plt.tight_layout()
plt.savefig('年龄分组生存率.png', dpi=300)
plt.show()6.3 相关性可视化:特征相关性热力图
直观展示数值型字段间的相关性,辅助验证分析结论:
# 提取数值型字段,计算相关性矩阵
numeric_cols = df.select_dtypes(include=[np.number]).columns # 筛选所有数值型字段
corr_matrix = df[numeric_cols].corr() # 计算皮尔逊相关系数矩阵
plt.figure(figsize=(10, 8))
# 绘制热力图:annot=True显示相关系数,cmap设置颜色映射(红=负相关,蓝=正相关)
sns.heatmap(corr_matrix, annot=True, cmap='RdBu_r', vmin=-1, vmax=1, linewidths=0.5)
plt.title('数值型字段相关性热力图', fontsize=14)
plt.tight_layout()
plt.savefig('特征相关性热力图.png', dpi=300)
plt.show()6.4 分布可视化:年龄分布(按生存标签分组)
展示不同生存状态下的年龄分布差异,辅助分析年龄对生存的影响:
# 图6:生存/死亡乘客的年龄分布直方图(叠层展示,清晰对比差异)
plt.figure(figsize=(10, 6))
sns.histplot(data=df, x='age', hue='survived', multiple='stack',
bins=20, palette=['#E74C3C', '#2ECC71'])
plt.title('生存/死亡乘客的年龄分布', fontsize=14)
plt.xlabel('年龄', fontsize=12)
plt.ylabel('人数', fontsize=12)
plt.legend(labels=['死亡', '生存']) # 修正图例标签
plt.tight_layout()
plt.savefig('年龄分布.png', dpi=300)
plt.show()步骤7:数据导出
若需将清洗后的数据集、分析结果导出为CSV/Excel文件,供后续报告撰写、其他工具(如Excel、Tableau)复用,Pandas提供简单易用的导出方法,需注意设置编码避免中文乱码:
# 1. 导出清洗后的完整数据集为CSV(无索引,方便后续复用)
df.to_csv('泰坦尼克号清洗后数据.csv', index=False, encoding='utf-8-sig') # utf-8-sig避免中文乱码
# 2. 导出核心分析结果(如客舱等级+性别生存率)为Excel文件
pclass_sex_survive.to_excel('客舱等级+性别生存率.xlsx', sheet_name='生存率分析')
print("数据导出完成!")四、核心分析结论总结
基于泰坦尼克号数据集的完整Pandas数据分析流程,我们提炼出影响乘客生存概率的关键因素(按重要性排序):
- 性别:女性生存率(74.2%)远高于男性(18.9%),是最核心的影响因素,直接反映了当时“女士优先”的救援原则;
- 客舱等级:一等舱生存率(62.9%)是三等舱(24.2%)的2.6倍,与乘客的财富、社会地位强相关,阶级差异在救援中体现明显;
- 年龄:儿童生存率最高(59.0%),老年生存率最低(34.7%),符合“优先救助老弱妇孺”的普遍救援逻辑;
- 家庭规模:小家庭(2-3人)生存率更高,单身乘客或大家庭(6人以上)因人员分散、照顾难度大,生存率偏低;
- 船票价格:与生存率呈正相关,本质是客舱等级的间接体现,票价越高,对应的客舱等级越高,生存率也越高。
五、Pandas数据分析核心技巧与避坑点
5.1 核心技巧(新手必记)
- DataFrame是核心:所有数据处理、分析操作均围绕DataFrame展开,熟练掌握head()、info()、describe()、value_counts()、corr(),可快速完成80%的数据探索;
- groupby是分析利器:多维度分组聚合(groupby([A,B])[C].agg([D,E]))是分类数据分析的核心,结合unstack()可实现行转列,大幅提升结果可读性;
- 链式操作简化代码:Pandas支持链式操作(如df.dropna().fillna(0).groupby('A')['B'].mean()),可将多个操作合并,减少代码冗余;
- 分箱函数实用高效:cut()/qcut()可将连续数值(如年龄、票价)转为分类变量,方便分组分析,是特征工程的基础方法;
- 可视化优先选Seaborn:Seaborn原生适配Pandas DataFrame,无需手动转换数据,一行代码即可绘制美观图表,大幅提升可视化效率。
5.2 常见避坑点(新手高频错误)
- 中文乱码问题:必须提前设置Matplotlib的中文字体和负号显示(plt.rcParams相关配置),否则图表中文会显示为乱码;
- 缺失值处理盲目:避免无脑删除缺失值,需结合缺失率+字段含义选择填充/删除方法,数值型字段优先用中位数填充(抗异常值能力强于均值);
- 数据类型忽视:分类变量未转为category类型,会占用大量内存,尤其处理大数据集时,会显著降低运算速度;
- 索引混乱问题:删除行/列后,DataFrame索引可能不连续,需用df.reset_index(drop=True)重置索引,避免后续操作报错;
- 导出中文乱码:导出CSV/Excel文件时,需设置encoding='utf-8-sig'(CSV),否则中文会显示为乱码,影响后续复用。
六、拓展方向(从入门到实战)
本次流程为基础版数据分析,适用于绝大多数结构化数据(如电商用户数据、金融交易数据、医疗数据),实际工作中可根据需求拓展以下方向,提升分析深度:
- 高级特征工程:对分类变量(如embarked)做独热编码(pd.get_dummies()),对文本字段(如name)提取特征(如头衔Mr/Mrs/Miss),为机器学习建模做准备;
- 统计检验:用卡方检验(分类变量)、独立样本T检验(数值变量),验证特征与目标变量(如survived)的相关性是否显著,增强分析结论的说服力;
- 机器学习建模:基于清洗后的特征,构建逻辑回归、决策树等分类模型,预测乘客生存概率,实现“分析→预测”的进阶;
- 交互式可视化:结合Plotly、Altair等工具,实现交互式可视化,支持鼠标悬停查看详细数据,提升报告的交互性;
- 多数据集合并:若有泰坦尼克号的船员数据、救援数据,可用pd.merge()、pd.concat()实现多数据集合并分析,挖掘更全面的规律。
七、总结
本文以泰坦尼克号数据集为例,完整演示了用Pandas完成数据分析的全流程,从环境准备、数据加载、探索性分析,到核心的数据清洗、特征工程、分组分析,再到可视化呈现与数据导出,覆盖了新手入门所需的全部核心知识点与实操技巧。需要注意的是,数据分析的核心不在于“代码有多复杂”,而在于“逻辑有多清晰”——先通过探索性分析发现问题,再针对性进行数据清洗,最后通过合理的分析方法挖掘数据规律,并用可视化呈现结果。这套流程具有极强的通用性,只需根据具体业务场景,调整清洗规则、特征工程方法与分析维度,即可快速完成各类结构化数据的分析工作,帮助大家高效解决实际业务问题。
版权所属:SO JSON在线解析
原文地址:https://www.sojson.com/blog/575.html
转载时必须以链接形式注明原始出处及本声明。
如果本文对你有帮助,那么请你赞助我,让我更有激情的写下去,帮助更多的人。
