第三章:Matplotlib 与数据分析 第三章:Matplotlib 与数据分析 3.1 Matplotlib 在数据分析中的作用 在数据分析的各个阶段,Matplotlib 都扮演着重要的角色: 数据探索性分析 (Exploratory Data Analysis, EDA): 在初步接触数据集时,我们需要快速了解数据的基本特征、分布情况以及变量之间的关系。Matplotlib 提供了多种图表类型,如直方图、散点图、箱线图等,可以帮助我们快速进行 EDA,发现数据中的异常值、模式和关联性。 数据可视化呈现 (Data Visualization for Presentation): 数据分析的结果最终需要有效地传达给他人。
在数据分析的各个阶段,Matplotlib 都扮演着重要的角色:
数据探索性分析 (Exploratory Data Analysis, EDA): 在初步接触数据集时,我们需要快速了解数据的基本特征、分布情况以及变量之间的关系。Matplotlib 提供了多种图表类型,如直方图、散点图、箱线图等,可以帮助我们快速进行 EDA,发现数据中的异常值、模式和关联性。
数据可视化呈现 (Data Visualization for Presentation): 数据分析的结果最终需要有效地传达给他人。Matplotlib 可以生成高质量的图表,用于报告、演示文稿或学术论文中,清晰地展示分析结论,增强沟通效果。
模型诊断与评估 (Model Diagnostics and Evaluation): 在机器学习和统计建模中,可视化模型预测结果、残差分布、特征重要性等信息,有助于我们诊断模型性能、发现潜在问题,并进行模型优化。
总而言之,Matplotlib 就像数据分析师的“眼睛”,它将抽象的数据转化为可视化的形式,帮助我们更深入地理解数据,并有效地传达数据分析的洞见。
在深入数据分析应用之前,我们先简要回顾 Matplotlib 的基础知识和核心概念。
Matplotlib 的架构主要分为三个层次:
backend_agg 层 (后端层): 负责实际的图形渲染,将图表绘制成图像文件(如 PNG, JPG, SVG 等)。用户通常不需要直接与后端层交互。
artist 层 (艺术家层): 这是 Matplotlib 的核心层,包含了所有用于绘图的“艺术家”对象,例如 Figure (画布)、Axes (坐标轴)、Line2D (线条)、Text (文本)、Rectangle (矩形) 等。每个图表元素都是一个 Artist 对象。
pyplot 层 (脚本层): pyplot 模块提供了一套方便的函数,允许用户以类似于 MATLAB 的方式创建和操作图表。它是用户最常接触的层,简化了绘图过程。
在实际应用中,我们通常使用 pyplot 模块来快速创建图表,并通过 Artist 对象进行更精细的定制。
Figure (画布): 是整个图表的容器,可以包含多个 Axes 对象。你可以把它想象成一张大的画布。
Axes (坐标轴): 是实际绘图的区域,每个 Axes 对象代表一个独立的坐标系,可以绘制各种图表元素(线条、散点、柱状图等)。一个 Figure 可以包含多个 Axes,形成子图。
理解 Figure 和 Axes 的关系至关重要。创建图表的第一步通常是创建一个 Figure 对象,然后在 Figure 对象中添加一个或多个 Axes 对象。
Matplotlib 支持丰富的图表类型,常用的数据分析图表包括:
折线图 (Line Plot): 用于展示数据随时间或连续变量变化的趋势。
散点图 (Scatter Plot): 用于展示两个变量之间的关系,观察是否存在相关性。
柱状图 (Bar Chart): 用于比较不同类别或组别的数据大小。
直方图 (Histogram): 用于展示单个变量的分布情况,了解数据的集中趋势和离散程度。
箱线图 (Box Plot): 用于展示数据的五数概括(最小值、下四分位数、中位数、上四分位数、最大值)以及异常值。
饼图 (Pie Chart): 用于展示各部分占整体的比例。
热力图 (Heatmap): 用于展示矩阵数据的分布情况,通常用颜色深浅表示数值大小。
接下来,我们将通过代码示例详细介绍如何使用 Matplotlib 绘制数据分析中常用的图表,并解释代码背后的原理和应用场景。
环境准备:
首先,确保你已经安装了 Matplotlib 和 NumPy 库。如果没有安装,可以使用 pip 命令安装:
pip install matplotlib numpy
代码示例 3.3.1: 折线图 (Line Plot) - 趋势分析
折线图是最常用的图表类型之一,尤其适用于展示时间序列数据的趋势变化。
import matplotlib.pyplot as plt import numpy as np # 模拟时间序列数据 (例如,每日温度) days = np.arange(1, 31) # 1到30天 temperature = np.random.uniform(15, 30, size=30) + np.sin(days * np.pi / 15) * 5 # 模拟温度波动 # 创建 Figure 和 Axes 对象 fig, ax = plt.subplots(figsize=(10, 6)) # figsize 设置图表大小 # 绘制折线图 ax.plot(days, temperature, marker='o', linestyle='-', color='skyblue', label='Daily Temperature') # marker 添加数据点标记,linestyle 设置线条样式 # 添加标题和轴标签 ax.set_title('Daily Temperature Variation in July', fontsize=16) ax.set_xlabel('Day of Month', fontsize=12) ax.set_ylabel('Temperature (°C)', fontsize=12) # 添加网格线 ax.grid(True, linestyle='--', alpha=0.7) # alpha 设置透明度 # 添加图例 ax.legend(loc='upper left') # loc 设置图例位置 # 设置 x 轴刻度 ax.set_xticks(days[::3]) # 每隔3天显示一个刻度 # 显示图表 plt.tight_layout() # 自动调整子图参数,使图形更紧凑 plt.show()
代码详解:
import matplotlib.pyplot as plt 和 import numpy as np: 导入必要的库。plt 是 matplotlib.pyplot 的常用别名,np 是 numpy 的常用别名。
模拟数据: 使用 numpy 生成模拟的日期和温度数据。np.random.uniform 生成均匀分布的随机数,np.sin 生成正弦波模拟温度的周期性波动。
fig, ax = plt.subplots(figsize=(10, 6)): 创建 Figure 和 Axes 对象。plt.subplots() 函数返回一个包含 Figure 对象和 Axes 对象的元组。figsize 参数设置图表的大小,单位为英寸。
ax.plot(days, temperature, marker='o', linestyle='-', color='skyblue', label='Daily Temperature'): 使用 ax.plot() 函数绘制折线图。
days 作为 x 轴数据,temperature 作为 y 轴数据。
marker='o' 设置数据点标记为圆圈。
linestyle='-' 设置线条样式为实线。
color='skyblue' 设置线条颜色为天蓝色。
label='Daily Temperature' 设置图例标签。
ax.set_title(...), ax.set_xlabel(...), ax.set_ylabel(...): 分别设置图表标题、x 轴标签和 y 轴标签。fontsize 参数设置字体大小。
ax.grid(True, linestyle='--', alpha=0.7): 添加网格线。True 表示显示网格线,linestyle='--' 设置线条样式为虚线,alpha=0.7 设置透明度为 0.7。
ax.legend(loc='upper left'): 添加图例。loc='upper left' 设置图例位置为左上角。
ax.set_xticks(days[::3]): 设置 x 轴刻度。days[::3] 表示每隔 3 天取一个日期作为刻度。
plt.tight_layout(): 自动调整子图参数,使图形更紧凑,避免标签或标题重叠。
plt.show(): 显示图表。
应用场景: 折线图适用于展示时间序列数据的变化趋势,例如股票价格走势、用户访问量变化、产品销量变化等。通过观察折线图,我们可以快速识别数据的增长、下降、波动等趋势,并进行趋势预测和分析。
代码示例 3.3.2: 散点图 (Scatter Plot) - 关系分析
散点图用于展示两个变量之间的关系,帮助我们判断变量之间是否存在相关性。
import matplotlib.pyplot as plt import numpy as np # 模拟身高和体重数据 np.random.seed(42) # 设置随机种子,保证结果可重复 height = np.random.normal(170, 10, 100) # 平均身高 170cm,标准差 10cm weight = height * 0.6 + np.random.normal(0, 5, 100) # 体重与身高正相关,并加入随机噪声 # 创建 Figure 和 Axes 对象 fig, ax = plt.subplots(figsize=(8, 6)) # 绘制散点图 ax.scatter(height, weight, color='coral', alpha=0.8, label='Height vs. Weight') # alpha 设置点的透明度 # 添加标题和轴标签 ax.set_title('Relationship between Height and Weight', fontsize=16) ax.set_xlabel('Height (cm)', fontsize=12) ax.set_ylabel('Weight (kg)', fontsize=12) # 添加网格线 ax.grid(True, linestyle='--', alpha=0.5) # 添加图例 ax.legend() # 显示图表 plt.tight_layout() plt.show()
代码详解:
np.random.seed(42): 设置随机种子,确保每次运行代码生成的随机数据相同,方便结果的可重复性。
模拟数据: 使用 np.random.normal 生成模拟的身高和体重数据。体重数据与身高数据呈正相关关系,并加入了随机噪声,模拟真实世界数据的复杂性。
ax.scatter(height, weight, color='coral', alpha=0.8, label='Height vs. Weight'): 使用 ax.scatter() 函数绘制散点图。
height 作为 x 轴数据,weight 作为 y 轴数据。
color='coral' 设置点的颜色为珊瑚色。
alpha=0.8 设置点的透明度为 0.8,使点在重叠时也能清晰显示。
应用场景: 散点图适用于分析两个变量之间的关系,例如广告投入与销售额的关系、学习时长与考试成绩的关系、房屋面积与房价的关系等。通过观察散点图的分布趋势,我们可以判断变量之间是否存在线性关系、非线性关系,以及是否存在异常值。
代码示例 3.3.3: 柱状图 (Bar Chart) - 类别比较
柱状图用于比较不同类别或组别的数据大小。
import matplotlib.pyplot as plt import numpy as np # 模拟不同产品的销量数据 products = ['Product A', 'Product B', 'Product C', 'Product D', 'Product E'] sales = np.array([250, 380, 150, 450, 300]) # 创建 Figure 和 Axes 对象 fig, ax = plt.subplots(figsize=(8, 6)) # 绘制柱状图 ax.bar(products, sales, color=['skyblue', 'lightcoral', 'lightgreen', 'gold', 'plum']) # 可以为不同柱子设置不同颜色 # 添加标题和轴标签 ax.set_title('Sales Performance of Different Products', fontsize=16) ax.set_xlabel('Product Name', fontsize=12) ax.set_ylabel('Sales Quantity', fontsize=12) # 在柱子上添加数值标签 for i, v in enumerate(sales): ax.text(i, v + 5, str(v), ha='center', va='bottom') # ha 水平对齐,va 垂直对齐 # 调整 x 轴刻度位置,使其居中于柱子下方 ax.set_xticks(np.arange(len(products))) ax.set_xticklabels(products) # 设置 x 轴刻度标签 # 显示图表 plt.tight_layout() plt.show()
代码详解:
模拟数据: 定义产品名称列表 products 和销量数据 sales。
ax.bar(products, sales, color=['skyblue', 'lightcoral', 'lightgreen', 'gold', 'plum']): 使用 ax.bar() 函数绘制柱状图。
products 作为 x 轴刻度标签,sales 作为柱子的高度。
color 参数可以传入颜色列表,为每个柱子设置不同的颜色。
添加数值标签: 使用 ax.text() 函数在每个柱子的顶部添加数值标签。
enumerate(sales) 遍历销量数据,同时获取索引 i 和数值 v。
ax.text(i, v + 5, str(v), ha='center', va='bottom') 在坐标 (i, v + 5) 处添加文本标签 str(v)。ha='center' 设置水平居中对齐,va='bottom' 设置垂直底部对齐。
ax.set_xticks(np.arange(len(products))) 和 ax.set_xticklabels(products): 设置 x 轴刻度位置和标签,使刻度标签居中于柱子下方。
应用场景: 柱状图适用于比较不同类别或组别的数据大小,例如不同产品的销量比较、不同地区的 GDP 比较、不同年龄段的人数比较等。通过观察柱状图的高度,我们可以直观地比较各类别之间的数据差异。
代码示例 3.3.4: 直方图 (Histogram) - 分布分析
直方图用于展示单个变量的分布情况,了解数据的集中趋势和离散程度。
import matplotlib.pyplot as plt import numpy as np # 模拟学生成绩数据 np.random.seed(42) scores = np.random.normal(75, 15, 200) # 平均分 75,标准差 15,共 200 个学生 # 创建 Figure 和 Axes 对象 fig, ax = plt.subplots(figsize=(8, 6)) # 绘制直方图 ax.hist(scores, bins=10, color='lightseagreen', edgecolor='black', alpha=0.7) # bins 设置柱子数量,edgecolor 设置柱子边框颜色 # 添加标题和轴标签 ax.set_title('Distribution of Student Scores', fontsize=16) ax.set_xlabel('Score Range', fontsize=12) ax.set_ylabel('Frequency', fontsize=12) # 添加网格线 ax.grid(axis='y', linestyle='--', alpha=0.7) # axis='y' 只显示 y 轴网格线 # 显示图表 plt.tight_layout() plt.show()
代码详解:
ax.hist(scores, bins=10, color='lightseagreen', edgecolor='black', alpha=0.7): 使用 ax.hist() 函数绘制直方图。
scores 是要绘制直方图的数据。
bins=10 设置柱子的数量为 10,即把数据范围分成 10 个区间。
color='lightseagreen' 设置柱子颜色为浅海绿色。
edgecolor='black' 设置柱子边框颜色为黑色。
ax.grid(axis='y', linestyle='--', alpha=0.7): 只显示 y 轴网格线,使频率的读取更方便。
应用场景: 直方图适用于分析单个变量的分布情况,例如用户年龄分布、收入分布、产品尺寸分布等。通过观察直方图的形状,我们可以判断数据是否服从正态分布、偏态分布,以及是否存在多个峰值。
代码示例 3.3.5: 箱线图 (Box Plot) - 数据概括与异常值检测
箱线图用于展示数据的五数概括(最小值、下四分位数、中位数、上四分位数、最大值)以及异常值。
import matplotlib.pyplot as plt import numpy as np # 模拟不同班级的考试成绩数据 np.random.seed(42) class_a_scores = np.random.normal(70, 12, 50) class_b_scores = np.random.normal(75, 10, 50) class_c_scores = np.random.normal(80, 8, 50) all_scores = [class_a_scores, class_b_scores, class_c_scores] # 将不同班级的数据放入列表 # 创建 Figure 和 Axes 对象 fig, ax = plt.subplots(figsize=(8, 6)) # 绘制箱线图 ax.boxplot(all_scores, labels=['Class A', 'Class B', 'Class C'], patch_artist=True, boxprops=dict(facecolor='lightblue', color='black'), # 箱体样式 whiskerprops=dict(color='black'), # 须线样式 capprops=dict(color='black'), # 箱须末端横线样式 medianprops=dict(color='red')) # 中位数线样式 # 添加标题和轴标签 ax.set_title('Comparison of Scores across Classes', fontsize=16) ax.set_xlabel('Class', fontsize=12) ax.set_ylabel('Score', fontsize=12) # 添加网格线 ax.grid(axis='y', linestyle='--', alpha=0.7) # 显示图表 plt.tight_layout() plt.show()
代码详解:
模拟数据: 模拟三个班级的考试成绩数据,并将它们放入列表 all_scores 中。
ax.boxplot(all_scores, labels=['Class A', 'Class B', 'Class C'], ...): 使用 ax.boxplot() 函数绘制箱线图。
all_scores 是要绘制箱线图的数据列表,每个元素代表一个箱线图的数据。
labels=['Class A', 'Class B', 'Class C'] 设置每个箱线图的标签。
patch_artist=True 允许自定义箱体的填充颜色。
boxprops, whiskerprops, capprops, medianprops 参数分别用于自定义箱体、须线、箱须末端横线和中位数线的样式。这里设置了箱体填充颜色为浅蓝色,边框、须线和箱须末端横线为黑色,中位数线为红色。
应用场景: 箱线图适用于比较不同组别数据的分布特征,以及检测数据中的异常值。通过观察箱线图的箱体位置、长度、须线长度以及异常点,我们可以比较不同组别数据的中心位置、离散程度和偏态情况,并识别可能的异常值。
代码示例 3.3.6: 饼图 (Pie Chart) - 比例展示
饼图用于展示各部分占整体的比例。
import matplotlib.pyplot as plt # 模拟不同渠道的销售额占比数据 channels = ['Online Store', 'Retail Store', 'Direct Sales', 'Distributors'] sales_percentage = [40, 30, 15, 15] colors = ['gold', 'lightcoral', 'lightskyblue', 'lightgreen'] explode = (0.1, 0, 0, 0) # explode the 1st slice (Online Store) # 创建 Figure 和 Axes 对象 fig, ax = plt.subplots(figsize=(8, 6)) # 绘制饼图 ax.pie(sales_percentage, explode=explode, labels=channels, colors=colors, autopct='%1.1f%%', shadow=True, startangle=90) # autopct 显示百分比,shadow 添加阴影,startangle 设置起始角度 # 设置标题 ax.set_title('Sales Distribution by Channel', fontsize=16) # 保证饼图是圆形 ax.axis('equal') # 显示图表 plt.tight_layout() plt.show()
代码详解:
模拟数据: 定义销售渠道列表 channels 和销售额占比数据 sales_percentage。colors 定义饼图各部分的颜色,explode 定义饼图的“爆炸”效果,突出显示第一部分。
ax.pie(sales_percentage, explode=explode, labels=channels, colors=colors, ...): 使用 ax.pie() 函数绘制饼图。
sales_percentage 是要绘制饼图的数据,表示各部分的比例。
explode=explode 设置饼图的“爆炸”效果。
labels=channels 设置饼图各部分的标签。
colors=colors 设置饼图各部分的颜色。
autopct='%1.1f%%' 设置在饼图上显示百分比,格式为保留一位小数的浮点数后跟百分号。
shadow=True 添加阴影效果。
startangle=90 设置饼图的起始角度为 90 度(从 y 轴正方向开始)。
ax.axis('equal'): 保证饼图是圆形,而不是椭圆形。
应用场景: 饼图适用于展示各部分占整体的比例,例如市场份额分布、支出结构分布、用户来源渠道分布等。通过观察饼图扇形的大小,我们可以直观地比较各部分所占的比例大小。
代码示例 3.3.7: 热力图 (Heatmap) - 矩阵数据可视化
热力图用于展示矩阵数据的分布情况,通常用颜色深浅表示数值大小。
import matplotlib.pyplot as plt import numpy as np # 模拟相关系数矩阵数据 np.random.seed(42) corr_matrix = np.random.rand(10, 10) # 生成 10x10 的随机矩阵 corr_matrix = (corr_matrix + corr_matrix.T) / 2 # 使矩阵对称,模拟相关系数矩阵 np.fill_diagonal(corr_matrix, 1) # 对角线元素设为 1 features = [f'Feature {i+1}' for i in range(10)] # 特征名称列表 # 创建 Figure 和 Axes 对象 fig, ax = plt.subplots(figsize=(10, 8)) # 绘制热力图 im = ax.imshow(corr_matrix, cmap='coolwarm', vmin=-1, vmax=1) # cmap 设置颜色映射,vmin 和 vmax 设置颜色范围 # 添加颜色刻度条 cbar = ax.figure.colorbar(im, ax=ax) cbar.ax.set_ylabel('Correlation Coefficient', rotation=-90, va="bottom") # 设置刻度标签 ax.set_xticks(np.arange(len(features))) ax.set_yticks(np.arange(len(features))) ax.set_xticklabels(features) ax.set_yticklabels(features) # 旋转 x 轴刻度标签,使其更易读 plt.setp(ax.get_xticklabels(), rotation=45, ha="right", rotation_mode="anchor") # 在热力图上添加数值标签 for i in range(len(features)): for j in range(len(features)): text = ax.text(j, i, f'{corr_matrix[i, j]:.2f}', ha="center", va="center", color="black") # 保留两位小数 # 设置标题 ax.set_title('Correlation Matrix of Features', fontsize=16) # 使布局紧凑 plt.tight_layout() plt.show()
代码详解:
模拟数据: 模拟一个 10x10 的相关系数矩阵 corr_matrix。相关系数矩阵是一个对称矩阵,对角线元素为 1,取值范围通常在 -1 到 1 之间。
ax.imshow(corr_matrix, cmap='coolwarm', vmin=-1, vmax=1): 使用 ax.imshow() 函数绘制热力图。
corr_matrix 是要绘制热力图的矩阵数据。
cmap='coolwarm' 设置颜色映射为 'coolwarm',表示从冷色(蓝色)到暖色(红色)的渐变,中间色为白色,适合表示相关系数,正相关为暖色,负相关为冷色。
vmin=-1 和 vmax=1 设置颜色映射的数值范围,与相关系数的取值范围一致。
cbar = ax.figure.colorbar(im, ax=ax): 添加颜色刻度条,显示颜色与数值的对应关系。
设置刻度标签和旋转 x 轴刻度标签: 设置 x 轴和 y 轴的刻度标签为特征名称,并旋转 x 轴刻度标签,使其更易读。
在热力图上添加数值标签: 使用 ax.text() 函数在每个单元格中添加数值标签,显示相关系数的具体数值。
应用场景: 热力图适用于可视化矩阵数据,例如相关系数矩阵、混淆矩阵、距离矩阵等。通过观察热力图的颜色深浅,我们可以快速识别矩阵中数值的大小分布和模式。在数据分析中,热力图常用于分析特征之间的相关性、聚类分析的结果展示等。
为了更好地理解 Matplotlib 在数据分析流程中的位置和作用,我们可以使用 Mermaid 图表绘制一个简单的数据分析流程图。
图表解释:
数据收集 (A): 数据分析的第一步是收集数据,数据可以来自各种来源,例如数据库、文件、API 等。
数据清洗 (B): 收集到的数据通常包含缺失值、异常值、重复值等问题,需要进行数据清洗,保证数据质量。
数据探索性分析 (EDA) (C): 使用统计方法和可视化工具(例如 Matplotlib)初步了解数据的基本特征、分布情况和变量关系。
特征工程 (D): 根据业务理解和数据分析目标,从原始数据中提取、转换或创建新的特征,为模型构建做准备。
模型构建 (E): 选择合适的模型算法,使用处理后的数据进行模型训练。
模型评估 (F): 评估模型在测试集上的性能,判断模型是否满足需求,是否需要优化。
模型部署/结果呈现 (G): 将训练好的模型部署到生产环境,或者将数据分析结果以报告、仪表盘等形式呈现给用户。
Matplotlib 可视化 (H): 在数据探索性分析 (EDA) 阶段,Matplotlib 用于生成各种图表,帮助我们理解数据;在模型评估和结果呈现阶段,Matplotlib 也可以用于可视化模型性能指标和分析结果。
报告/决策 (I): 基于数据分析结果和可视化呈现,生成分析报告,为业务决策提供支持。
Mermaid 语法解释:
graph TD:定义图表类型为流程图 (Top-down direction)。