49  数据框可视化

49.1 引言 数据可视化的价值

理论背景:可视化与数据理解

数据可视化(Data Visualization)是将抽象数据转换为图形表示的过程。在金融数据分析中,可视化扮演着不可替代的角色:

  1. 模式发现:人类视觉系统对模式和异常的识别能力远强于对数字表格的扫描能力
  2. 沟通工具:一张精心设计的图表往往比千言万语更能传达数据洞察
  3. 决策支持:可视化帮助决策者快速理解数据趋势,做出更明智的商业决策

数学基础:视觉编码的原理

数据可视化的本质是将数据属性(数值、类别、时间)映射到视觉通道(位置、长度、颜色、形状)。有效的可视化应该遵循可视化曼哈顿原则:在单位面积内编码尽可能多的信息,同时保持可读性。

Pandas与Matplotlib、Seaborn的集成形成了一个完整的Python可视化生态系统: - Matplotlib:底层绘图库,提供完整的控制能力 - Seaborn:基于Matplotlib的高级接口,专为统计可视化设计 - Pandas:.plot()方法提供快速绘图能力

49.2 基础图表绘制

折线图和柱状图是金融分析中最常用的两种图表类型。

列表 49.1
# =============================================================================
# 题目:绘制基础金融图表
# =============================================================================
# 本任务演示如何使用Matplotlib绘制折线图和柱状图

# ==================== 导入必要的库 ====================
import matplotlib.pyplot as plt  # Matplotlib的 pyplot 接口,提供类似 MATLAB 的绘图API
import pandas as pd                 # Pandas 数据分析库
import seaborn as sns               # Seaborn 统计可视化库

# ==================== 设置中文字体支持 ====================
# Matplotlib默认不支持中文显示,需要手动设置中文字体
# plt.rcParams是一个全局配置字典,用于控制绘图的各种属性
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置默认字体为黑体(SimHei)
# plt.rcParams['axes.unicode_minus'] = False     # 解决负号'-'显示为方块的问题
# 这两行设置确保图表中的中文文字和负号都能正确显示

# ==================== 准备示例数据 ====================
# 场景:模拟公司5个月的销售额和利润数据
sales = pd.DataFrame({
    '月份': ['1月', '2月', '3月', '4月', '5月'],        # 时间维度(X轴)
    '销售额': [120, 150, 180, 140, 200],             # 销售额数据(用于折线图和柱状图)
    '利润': [30, 40, 50, 35, 60]                      # 利润数据(用于柱状图)
})

# ==================== 创建图形画布 ====================
# plt.figure()创建一个新的图形窗口
# figsize=(12, 6)指定图形大小为12英寸宽×6英寸高
# 这个比例适合并排显示两个子图
plt.figure(figsize=(12, 6))

# ==================== 绘制第一个子图:折线图 ====================
# plt.subplot(1, 2, 1)创建一个1行2列的子图布局,并激活第1个子图
# 三个参数的含义:(行数, 列数, 当前子图编号)
plt.subplot(1, 2, 1)

# plt.plot()绘制折线图
# sales['月份']:X轴数据(月份)
# sales['销售额']:Y轴数据(销售额)
# marker='o':在每个数据点处绘制圆形标记
# linewidth=2:设置线条宽度为2(使折线更明显)
plt.plot(sales['月份'], sales['销售额'], marker='o', linewidth=2)

# 设置标题和标签
plt.title('销售额趋势', fontsize=14)              # 设置图表标题,字号14
plt.xlabel('月份', fontsize=12)                      # 设置X轴标签
plt.ylabel('销售额(万元)', fontsize=12)               # 设置Y轴标签
plt.grid(True, alpha=0.3)                            # 添加网格线,alpha=0.3设置透明度(使网格不明显)

# ==================== 绘制第二个子图:柱状图 ====================
# plt.subplot(1, 2, 2)激活第2个子图
plt.subplot(1, 2, 2)

# plt.bar()绘制柱状图
# sales['月份']:X轴数据(月份)
# sales['利润']:柱子高度(利润)
# color='steelblue':设置柱子颜色为钢蓝色
# alpha=0.7:设置透明度(0.7使柱子有轻微透明效果)
plt.bar(sales['月份'], sales['利润'], color='steelblue', alpha=0.7)

# 设置标题和标签
plt.title('利润对比', fontsize=14)                  # 设置图表标题
plt.xlabel('月份', fontsize=12)                        # 设置X轴标签
plt.ylabel('利润(万元)', fontsize=12)                 # 设置Y轴标签
plt.grid(axis='y', alpha=0.3)                         # 只显示Y轴网格线(水平网格线)

# ==================== 调整布局并显示图表 ====================
# plt.tight_layout()自动调整子图之间的间距,防止标签重叠
plt.tight_layout()
# plt.show()将图形显示出来
plt.show()

49.3 Seaborn高级统计图表

Seaborn在Matplotlib基础上提供了更高级的统计可视化功能,特别适合展示数据的分布特征和统计关系。

列表 49.2
# =============================================================================
# 题目:绘制Seaborn高级统计图表
# =============================================================================
# 本任务演示如何使用Seaborn绘制箱线图和小提琴图来展示数据分布

# ==================== 导入Seaborn库 ====================
import seaborn as sns  # Seaborn统计可视化库

# ==================== 创建图形画布 ====================
plt.figure(figsize=(12, 6))

# ==================== 绘制第一个子图:箱线图 ====================
# plt.subplot(1, 2, 1)创建1行2列布局,激活第1个子图
plt.subplot(1, 2, 1)

# sns.boxplot()绘制箱线图(Boxplot)
# 箱线图显示数据的五个统计量:最小值、第一四分位数、中位数、第三四分位数、最大值
# 同时可以显示异常值(超出1.5倍IQR的数据点)
# data参数:数据源DataFrame
# x参数:X轴变量(分类变量,这里是月份)
# y参数:Y轴变量(数值变量,这里是销售额)
sns.boxplot(data=sales, x='月份', y='销售额')

# 设置标题
plt.title('销售额箱线图', fontsize=14)
# 箱线图的解读:
#   - 箱体:包含中间50%的数据(Q1到Q3)
#   - 箱中的横线:中位数
#   - 上下须:数据的正常范围(非异常值范围)
#   - 圆点:异常值(如果有的话)

# ==================== 绘制第二个子图:小提琴图 ====================
# plt.subplot(1, 2, 2)激活第2个子图
plt.subplot(1, 2, 2)

# sns.violinplot()绘制小提琴图(Violin Plot)
# 小提琴图结合了箱线图和核密度估计图,能更直观地展示数据分布形状
# 参数含义与boxplot相同
sns.violinplot(data=sales, x='月份', y='销售额')

# 设置标题
plt.title('销售额小提琴图', fontsize=14)
# 小提琴图的解读:
#   - 小提琴的宽度表示该位置数据点的密度
#   - 较宽的部分表示数据更集中
#   - 内部的箱线图元素显示统计量

# ==================== 调整布局并显示图表 ====================
plt.tight_layout()  # 自动调整子图间距
plt.show()         # 显示图形

49.4 散点图与回归分析

散点图是探索两个数值变量之间关系的经典工具。在金融分析中,散点图广泛用于研究两个变量(如股票价格与成交量、风险与收益)之间的相关性。

列表 49.3
# =============================================================================
# 题目:绘制散点图并添加回归线
# =============================================================================
# 本任务演示如何绘制散点图并拟合线性回归线

# ==================== 导入NumPy库 ====================
import numpy as np  # NumPy数值计算库,用于生成随机数

# ==================== 创建模拟数据 ====================
# 场景:模拟两个相关的金融变量(如风险与收益)
# 生成100个随机数据点
# np.random.randn(100)生成100个标准正态分布的随机数
# * 10 + 50将数据缩放和移位,使其均值约为50,标准差约为10
x = np.random.randn(100) * 10 + 50
# x表示自变量(如风险水平)

# 生成因变量y,与x正相关,但加入随机噪声
# x * 0.8:y与x的线性关系,斜率为0.8
# np.random.randn(100) * 5:添加随机噪声,标准差为5
# + 30:将数据移位,使均值约为30
y = x * 0.8 + np.random.randn(100) * 5 + 30
# y表示因变量(如收益),与x正相关但存在噪声

# ==================== 创建图形并绘制散点图 ====================
plt.figure(figsize=(10, 6))  # 创建10英寸宽×6英寸高的图形

# plt.scatter()绘制散点图
# x, y:X坐标和Y坐标数据
# alpha=0.6:设置透明度为0.6(使重叠的点更可见)
plt.scatter(x, y, alpha=0.6)

# ==================== 使用Seaborn添加回归线 ====================
# sns.regplot()绘制散点图并自动拟合线性回归线
# scatter_kws={'alpha':0.6}:将散点图的透明度设置为0.6(通过字典参数传递)
# Seaborn会自动:
#   1. 绘制散点图
#   2. 使用OLS(最小二乘法)拟合线性回归线
#   3. 绘制回归线和置信区间(阴影区域)
sns.regplot(x=x, y=y, scatter_kws={'alpha':0.6})

# ==================== 设置图形属性 ====================
plt.title('散点图与回归线', fontsize=14)
plt.xlabel('X变量', fontsize=12)
plt.ylabel('Y变量', fontsize=12)
plt.grid(True, alpha=0.3)    # 添加网格线,便于观察数据趋势
plt.tight_layout()            # 自动调整布局,防止标签被截断
plt.show()

# ==================== 图表解读 ====================
# 散点图显示了100个数据点的分布情况
# 回归线(红色直线)显示x和y的整体趋势
# 阴影区域表示回归线的置信区间(不确定性范围)
# 由于y = x * 0.8 + 噪声,回归线的斜率应该接近0.8

49.5 相关性热力图

热力图(Heatmap)是用颜色编码矩阵元素值的可视化方法。在金融分析中,热力图是展示相关性矩阵的最佳工具,可以一目了然地看出哪些变量之间存在强相关关系。

列表 49.4
# =============================================================================
# 题目:绘制相关性矩阵热力图
# =============================================================================
# 本任务演示如何计算相关系数矩阵并使用热力图可视化

# ==================== 准备示例数据 ====================
# 场景:模拟多个金融指标的数据,用于计算相关性
# 创建一个DataFrame,包含4个特征(A, B, C, D)和5个观测
data = pd.DataFrame({
    'A': [1, 2, 3, 4, 5],        # 特征A:递增序列
    'B': [5, 4, 3, 2, 1],        # 特征B:递减序列(与A负相关)
    'C': [2, 3, 4, 5, 6],        # 特征C:递增序列
    'D': [4, 5, 6, 7, 8]         # 特征D:递增序列
})

# ==================== 计算相关系数矩阵 ====================
# df.corr()方法计算所有列之间的Pearson相关系数
# Pearson相关系数衡量两个变量之间的线性相关程度
# 取值范围:[-1, 1]
#   - 1:完全正相关
#   - 0:无线性相关
#   - -1:完全负相关
corr = data.corr()
# 结果是一个4×4的矩阵(对称矩阵,对角线为1)

# ==================== 绘制热力图 ====================
plt.figure(figsize=(10, 8))  # 创建10×8英寸的图形

# sns.heatmap()绘制热力图
# corr:相关系数矩阵(数据源)
# annot=True:在每个格子中显示数值注释
# cmap='coolwarm':使用蓝-红配色方案(冷-暖色)
#   负相关显示为蓝色,正相关显示为红色
# center=0:设置颜色中心值为0,确保0值显示为中间色
# linewidths=0.5:格子之间的线宽
# cbar_kws={'label': '相关系数'}:颜色条的标签文本
sns.heatmap(
    corr,
    annot=True,
    cmap='coolwarm',
    center=0,
    linewidths=0.5,
    cbar_kws={'label': '相关系数'}
)

# 设置标题
plt.title('特征相关性热力图', fontsize=14)
plt.tight_layout()            # 调整布局
plt.show()

# ==================== 图表解读 ====================
# 热力图中的每个格子代表两个特征之间的相关系数
# 颜色越红:正相关越强(接近1)
# 颜色越蓝:负相关越强(接近-1)
# 颜色接近白色:相关性较弱(接近0)
# 对角线为1(自相关,总是完全相关)
#
# 从本例中可以看出:
#   - A与B:负相关(一个递增,一个递减)
#   - A与C、A与D、C与D等:正相关(都递增)

平台任务解答代码

以下代码与教学平台任务要求完全一致:

列表 49.5
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#任务一
import matplotlib.pyplot as plt
import pandas as pd  # 导入Pandas数据分析库

plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置Matplotlib全局参数
turnover = pd.read_excel("https://huoran.oss-cn-shenzhen.aliyuncs.com/1726219804739.xlsx",sheet_name="Sheet1")  #导入外部换手率数据并且是Sheet1工作表
turnover["日期"] = pd.to_datetime(turnover["日期"] , format='%Y%m%d')  # 转换为日期时间格式
turnover.set_index("日期",inplace=True)  # 将日期列设为turnover数据框的索引
turnover.head() #显示前五行
turnover.tail() #显示后五行
# 绘制换手率的折线图(显示时间趋势)
turnover.plot(kind="line",figsize=(9,6),title="2024年1月至2024年8月上证50指数换手率",grid=True,fontsize=13)
plt.savefig("1.png")  # 保存图形至文件

#任务二
import matplotlib.pyplot as plt
import pandas as pd  # 导入Pandas数据分析库
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置Matplotlib全局参数

# 从Excel文件读取数据存入volume
volume = pd.read_excel("https://huoran.oss-cn-shenzhen.aliyuncs.com/1726219804739.xlsx",sheet_name="Sheet2",header=0)  

volume["日期"] = pd.to_datetime(volume["日期"] , format='%Y%m%d')  # 转换为日期时间格式
volume.set_index("日期",inplace=True)  # 将日期列设为volume数据框的索引
# 绘制交易金额的直方图(展示分布特征)
volume.plot(kind="hist",figsize=(9,6),title="2024年1月至2024年9月上证50指数交易金额",grid=True,fontsize=13)
plt.savefig("1.png")  # 保存图形至文件


#任务三
import matplotlib.pyplot as plt
import pandas as pd  # 导入Pandas数据分析库
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置Matplotlib全局参数

# 从Excel文件读取数据存入volume
volume = pd.read_excel("https://huoran.oss-cn-shenzhen.aliyuncs.com/1726219804739.xlsx",sheet_name="Sheet2",header=0) 
volume["日期"] = pd.to_datetime(volume["日期"] , format='%Y%m%d')  # 转换为日期时间格式
volume.set_index("日期",inplace=True)  # 将日期列设为volume数据框的索引
volume.describe() #查看数据属性
# 绘制交易金额的箱线图(展示分位数和异常值)
volume.plot(kind="box",figsize=(9,6),title="2024年1月至2024年9月上证50指数交易金额",grid=True,fontsize=13)
plt.savefig("1.png")  # 保存图形至文件

#任务四
import matplotlib.pyplot as plt
import pandas as pd  # 导入Pandas数据分析库
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置Matplotlib全局参数

# 从Excel文件读取数据存入price
price = pd.read_excel("https://huoran.oss-cn-shenzhen.aliyuncs.com/1726219804739.xlsx",sheet_name="Sheet3")
price ["日期"] = pd.to_datetime(price["日期"] , format='%Y%m%d')  # 转换为日期时间格式
price.set_index("日期",inplace=True)  # 将日期列设为price数据框的索引
price.head()  # 查看price前5行数据
price.tail()  # 查看price后5行数据
price.plot(kind="line",subplots=True,sharex=True,sharey=True,layout=(2,2),figsize=(10,8),title="2024年1月至2024年9月上证50指数走势图",grid=True,fontsize=13) #2018年1月至2019年6月上证50指数走势图
plt.savefig("1.png")  # 保存图形至文件