01 数据的管理与探索

金融大数据

今日议题:我们如何从数据海洋中淘金?

我们的核心挑战,是如何不被海量数据淹没,并从中提取出能够驱动决策的 α (Alpha) 信号。

从数据海洋中淘金An illustration depicting the process of finding valuable signals (Alpha) within a vast sea of data. It shows a sieve extracting a glowing alpha symbol from a background of binary code, representing data noise.100111010011110101001011100011000101001111011110100100111100110011000000100111010100010100001011110100110011101011010111100001100011011001010101110001100100001101110101101100011011001010101110001100100001101110101101010111100001100011011001010101110001101101010001010000101111010011001110101110011101001111010100101110001100010100111101111010α海量数据 (噪音)有价值的信号 (Alpha)An arrow pointing from the data noise to the extracted signal.

本章目标:掌握数据分析的“三板斧”

今天课程结束时,你将掌握从原始数据中提取价值的核心三步。这三步构成了我们数据分析工作流的基石。

1. 理解数据存储

辨析不同存储介质与文件格式的优劣,为数据选择合适的“家”。

2. 掌握数据操纵

使用 Pandas 对数据进行读取、清洗、筛选、聚合与合并。

3. 实现数据可视化

Seaborn 将枯燥的数据转化为直观、有洞察力的图表。

本章目标图标Three icons representing the chapter's goals: Data Storage, Data Manipulation, and Data Visualization.

金融数据管理的挑战与机遇

金融数据不仅量大,而且复杂,这既是挑战也是机遇。高效的数据管理能力是区分业余和专业的关键。

挑战

  • 如何高效地存储、读取和处理 TB 甚至 PB 级别的数据?
  • 如何保证数据质量,避免“垃圾进,垃圾出”?
  • 如何在噪音中识别出微弱的信号?

机遇

  • 投资决策: 股市指标预测公司基本面。
  • 风险管理: 银行转账信息评估信用风险。
  • 监管科技: 识别异常交易模式。

本章学习路线图

我们将遵循一条从理论到工具,再到实践的清晰路径,确保你系统地掌握本章知识。

Chapter Roadmap A roadmap showing three stages: Theory, Tools, and Practice. 1. 理论基础 存储 & 格式 2. 核心工具 Pandas & Seaborn 3. 动手实践 数据探索 & 可视化

第一部分:数据住在哪里?

分析师的困境:速度 vs. 空间

在数据分析中,我们始终在两个核心存储设备之间进行权衡:内存 (RAM)硬盘 (Hard Drive/SSD)。理解它们的区别,是高效处理数据的第一步。

一个生动的类比:工作台 vs. 仓库

将内存和硬盘想象成你的工作台仓库,这能帮助你直观地理解它们各自的角色、优缺点和协同工作的模式。

内存与硬盘的类比:工作台与仓库An analogy comparing computer RAM to a fast but small workbench and a hard drive to a large but slow warehouse, illustrating the trade-offs in data processing.内存 (RAM)你的工作台✓ 速度极快✗ 空间有限 / 易失性硬盘 (HDD/SSD)你的仓库✓ 容量巨大 / 持久性✗ 速度相对较慢数据读写

内存与硬盘的协同工作流

数据分析的典型工作流完美体现了二者的协同:从硬盘(仓库)中调取数据到内存(工作台)进行处理,然后将结果存回硬盘。

Data Workflow between RAM and HDD A flowchart illustrating the data analysis workflow: from long-term storage on HDD, to processing in RAM, and saving results back to HDD. 硬盘 (仓库) 长期存储海量数据 内存 (工作台) 高速计算与分析 2. 读入数据进行分析 4. 将结果写回保存 1. 原始数据 3. 程序执行

内存 vs. 硬盘:核心特性对比

特性 内存 (RAM) 硬盘 (Hard Drive/SSD)
角色 工作区 (Workspace) 存储区 (Storage)
速度 极快 相对较慢
容量 较小 (8GB - 64GB) 巨大 (256GB - 数TB)
持久性 易失性 (断电即清空) 非易失性 (长期保存)
成本 每GB成本高 每GB成本低

数据格式:为数据选择合适的“容器”

数据不仅要选择存储设备,还要选择合适的文件格式。这决定了数据的结构、性能和通用性。我们将重点关注四种主流格式。

Four Key Data Formats Icons for four data formats: CSV, XLSX, JSON, and Parquet. CSV 通用文本 XLSX 电子表格 { } 网络数据 [ C ] 大数据

文件格式 1: CSV (逗号分隔值)

  • 结构: 纯文本,以逗号分隔值的表格数据。
  • 优点: 格式简单,人类可读性高,通用性极强。
  • 缺点: 无数据类型信息,处理大文件时读写慢,占用空间较大。
  • 金融用例: 分享小规模的日度收盘价数据。

文件格式 2: XLSX (Excel 工作簿)

  • 结构: 微软Excel的专有格式,支持多工作表、公式、图表。
  • 优点: 商业分析中最常用,支持丰富的数据类型和格式化。
  • 缺点: 格式复杂导致读写较慢,非纯文本,依赖特定库。
  • 金融用例: 制作需要格式化和图表的财务报告。

文件格式 3: JSON (JavaScript 对象表示法)

  • 结构: 纯文本,基于键值对的层次化数据结构。
  • 优点: 结构灵活清晰,人类可读性高,是网络API数据交换的标准。
  • 缺点: 对于大型表格数据,冗余信息多,效率不高。
  • 金融用例: 从券商API获取账户信息、订单状态等嵌套数据。

文件格式 4: Parquet (列式存储)

  • 结构: 二进制,列式存储,专为大数据分析设计。
  • 优点: 读写速度极快(特别是读取特定列时),压缩率高,自带数据类型。
  • 缺点: 二进制格式,人类不可直接阅读。
  • 金融用例: 存储海量历史高频交易数据、行情快照。

什么是“列式存储”?

行式存储(如CSV)像读书一样,一行一行存数据。列式存储(如Parquet)像查字典一样,一列一列存数据,这使其在分析查询时效率极高。

行式存储 vs. 列式存储An illustration comparing row-based vs column-based data storage on disk. Row-based shows interleaved data, while column-based shows contiguous data for each column, highlighting its efficiency for analytical queries.行式存储 (如 CSV)TickerPriceVolumeAAPL1501.2MGOOG2730800K硬盘布局:...列式存储 (如 Parquet)TickerPriceVolumeAAPL1501.2MGOOG2730800K硬盘布局:.........

四种数据格式的横向比较

文件类型 数据结构 读/写速度 (大数据) 人类可读性 典型用例
CSV 平面表格 高 (文本) 简单表格数据交换
XLSX 电子表格 中 (需软件) 商业、财务报告
JSON 层次化/键值对 高 (文本) 网络API、配置文件
Parquet 列式存储 极快 低 (二进制) 大数据分析、高效存储

第二部分:我们的核心工具

我们的核心工具(一): Pandas 简介

Pandas 是 Python 数据分析领域无可争议的王者

  • 核心: 提供了 DataFrame 对象,这是一个功能强大的内存数据表,可以看作是Python版的Excel。
  • 功能: 数据读写、清洗、筛选、切片、转换、聚合、合并…
  • 基石: 底层利用 NumPy 库进行数值计算,保证了运算效率。

Pandas 的核心:DataFrame 对象

一个DataFrame是一个二维的、大小可变的、异构的表格数据结构,带有标记的轴(行和列)。

Anatomy of a Pandas DataFrame A diagram showing the main components of a DataFrame: the Index, the Columns, and the Data. AAPL 150.5 1.2M GOOG 2730.1 800K TSLA 780.0 2.5M Ticker Price Volume 0 1 2 Columns (列) Index (索引) Data (数据)

Pandas 的核心优势:直观且强大

  • 标签对齐 操作自动按行和列的标签对齐,避免了手动管理的麻烦。

  • 轻松处理缺失值 提供了简单易用的方法来处理 NaN (Not a Number)。

  • 功能丰富 groupby, merge, pivot_table 等高级功能让复杂的数据操作变得简单。

  • 生态系统Matplotlib, Seaborn, Scikit-learn 等库无缝集成。

我们也必须了解Pandas的局限性

了解工具的边界同样重要。

1. 内存限制

Pandas 通常需要将整个数据集一次性读入内存。如果数据集比可用内存还大,Pandas 将无法处理。

Out of Memory ErrorAn illustration of a large dataset failing to fit into small RAM.50GB Dataset vs. 16GB RAMRAM (16GB)Data (50GB)内存溢出

2. 非原生SQL支持

Pandas 本身不执行SQL查询。要在DataFrame上使用SQL语法,需要借助 pandasql 等第三方库。

我们的核心工具(二): Matplotlib 简介

Matplotlib 是 Python 数据可视化的奠基者

  • 定位: 一个功能强大但相对底层的绘图库,提供了对图表每个元素的完全控制能力。
  • 优点: 灵活性极高,应用广泛,图表类型丰富。
  • 类比: Matplotlib 就像是画家的画笔和颜料,你可以画出任何你想要的东西,但这需要你手动调配。

我们的核心工具(三): Seaborn 简介

Seaborn 是基于 Matplotlib 的高级统计数据可视化库

  • 定位: 专注于绘制美观且信息丰富的统计图表。
  • 优点: 高级接口,美观默认值,与Pandas完美集成。
  • 类比: Seaborn 就像一个专业的图表设计师,你告诉他数据和主题,他就能迅速生成专业、美观的图表。

Matplotlib vs. Seaborn

Matplotlib vs. Seaborn Analogy An analogy comparing Matplotlib to a painter's palette (full control) and Seaborn to a design template (quick and professional). Matplotlib 画家的颜料盘:完全控制 Seaborn 设计师的模板:快速专业

第三部分:Pandas 实战演练

实战场景

我们将通过一个实际案例,一步步学习Pandas的核心操作。

场景: 我们有一份虚拟的投资者信息数据,包含ID、收入、性别和股票投资组合金额。

目标: 对这份数据进行读取、检查、筛选、扩展、聚合、合并,并最终保存。

步骤0: 准备工作环境和数据

在开始之前,我们需要导入Pandas库,并创建一个模拟的数据文件 income_stock.csv

为了保证结果可复现,我们使用 np.random.seed(42) 固定随机数。

import pandas as pd
import numpy as np
import os

# 设置随机种子以保证结果可复现
np.random.seed(42)

# --- 创建模拟数据 ---
data = {
    'id': [f'i_{i+1}' for i in range(10)],
    'income': np.random.randint(25000, 500000, 10),
    'gender': ['F', 'M', 'M', 'F', 'M', 'F', 'M', 'F', 'F', 'M'],
    'stock': np.random.uniform(15000, 250000, 10)
}
df_demo = pd.DataFrame(data)

# --- 创建另一个用于合并的数据 ---
gpa_data = {
    'id': [f'i_{i+1}' for i in range(10)],
    'gpa': np.round(np.random.uniform(2.0, 4.0, 10), 2)
}
df_gpa_demo = pd.DataFrame(gpa_data)

# --- 保存为CSV文件 ---
if not os.path.exists('data'):
    os.makedirs('data')
    
df_demo.to_csv('data/income_stock.csv', index=False)
df_gpa_demo.to_csv('data/gpa.csv', index=False)

print('演示数据 "income_stock.csv" 和 "gpa.csv" 已创建。')
演示数据 "income_stock.csv" 和 "gpa.csv" 已创建。

步骤1: 将数据从CSV文件读入内存

我们的第一个任务是将硬盘上的 income_stock.csv 文件加载到内存中的 Pandas DataFrame 中。

我们使用 pd.read_csv() 函数。

df = pd.read_csv('data/income_stock.csv')
print('数据成功读入名为 df 的 DataFrame 中。')
数据成功读入名为 df 的 DataFrame 中。

步骤2: 对数据进行第一次“侦察”

数据读入后,绝不能假设它是完美的。首先要快速检查它的基本情况。

  • 问题1: 数据长什么样?(预览)
  • 问题2: 数据有多大?(维度)
  • 问题3: 每列存储的是什么类型的数据?(类型)

侦察工具1: .head() - 快速预览数据

.head() 方法可以显示 DataFrame 的前5行(默认),让我们对数据结构有一个直观的认识。

df.head()
id income gender stock
0 i_1 146958 F 51658.712279
1 i_2 171867 M 28649.648860
2 i_3 156932 M 218551.394257
3 i_4 390838 F 156262.027760
4 i_5 284178 M 181397.055782

侦察工具2: .shape - 查看数据维度

.shape 属性返回一个元组,表示 (行数, 列数)。

df.shape
(10, 4)

解读: 这个输出 (10, 4) 告诉我们,这个数据集有 10 个观测样本(行),每个样本有 4 个特征(列)。

侦察工具3: .dtypes - 检查数据类型

.dtypes 属性告诉我们每一列存储的数据是什么格式。这是至关重要的一步,因为错误的类型会导致计算错误。

df.dtypes
id         object
income      int64
gender     object
stock     float64
dtype: object

解读: * incomeint64 (整数),正确。 * stockfloat64 (浮点数/小数),正确。 * idgenderobject,这通常表示文本(字符串),也正确。

步骤3: 数据选择与切片 - 获取你关心的部分

我们很少需要一次性处理整个数据集。更常见的操作是选择特定的列或行。

  • 选择列: 分析特定变量。
  • 选择行: 分析特定观测样本。

选择单列:使用方括号 []

要获取一个完整的列,可以使用 df['列名'] 的语法。这将返回一个 Pandas Series 对象。

stock_series = df['stock']
stock_series.head()
0     51658.712279
1     28649.648860
2    218551.394257
3    156262.027760
4    181397.055782
Name: stock, dtype: float64

选择多列:传递一个列表

要选择多个列,向方括号中传递一个包含列名的列表。

df[['id', 'income']].head()
id income
0 i_1 146958
1 i_2 171867
2 i_3 156932
3 i_4 390838
4 i_5 284178

选择单行:使用 .iloc[] 按位置索引

要根据行号(从0开始)选择一行,使用 .iloc[行号]

# 选择第一行 (索引为0)
user_0 = df.iloc
print(user_0)
<pandas.core.indexing._iLocIndexer object at 0x70f5c03b7ca0>

步骤4: 数据筛选 - 根据条件过滤数据

筛选是数据分析中最核心的操作之一。我们提出问题,然后用条件来过滤出答案。

核心思想:布尔掩码 (Boolean Masking)

布尔掩码 Part 1: 创建条件

首先,我们创建一个布尔条件。Pandas会逐行判断这个条件,返回一个由 True / False 组成的 Series。

问题: 哪些用户是男性?

# 创建一个布尔掩码
mask_male = (df['gender'] == 'M')
print(mask_male)
0    False
1     True
2     True
3    False
4     True
5    False
6     True
7    False
8    False
9     True
Name: gender, dtype: bool

布尔掩码 Part 2: 应用掩码

然后,将这个布尔 Series 放入 df[] 中,Pandas 会返回所有对应值为 True 的行。

# 从上一步获取掩码
mask_male = (df['gender'] == 'M')

# 将掩码应用于DataFrame
df_male = df[mask_male]
df_male.head()
id income gender stock
1 i_2 171867 M 28649.648860
2 i_3 156932 M 218551.394257
4 i_5 284178 M 181397.055782
6 i_7 135268 M 242928.815258
9 i_10 162337 M 57728.867294

多条件筛选:使用 & (与) 和 | (或)

当有多个条件时,需要用 & (and) 或 | (or) 连接。

重要: 每个条件都必须用括号 () 括起来!

问题: 筛选出性别为男 并且 收入 > 300,000 的用户。

df_male_highinc = df[(df['gender'] == 'M') & (df['income'] > 300000)]
print(df_male_highinc)
Empty DataFrame
Columns: [id, income, gender, stock]
Index: []

步骤5: 创建新变量 - 特征工程的基础

通常,原始数据本身不足以回答问题。我们需要基于现有变量创建新的、更有意义的变量(特征)。

问题: 用户的投资额占其收入的比例是多少?

创建新列:直接赋值

我们可以像给字典赋值一样,直接创建一个新列。

df['stock_income_ratio'] = df['stock'] / df['income'] 
df.head()
id income gender stock stock_income_ratio
0 i_1 146958 F 51658.712279 0.351520
1 i_2 171867 M 28649.648860 0.166697
2 i_3 156932 M 218551.394257 1.392650
3 i_4 390838 F 156262.027760 0.399813
4 i_5 284178 M 181397.055782 0.638322

解读: 一个名为 stock_income_ratio 的新列被创建出来,它的值是每一行 stock 除以 income 的结果。

步骤6: 数据汇总与聚合 - 从细节到宏观

我们经常需要从个体数据中计算出汇总统计量,以了解数据的宏观特征。

  • 问题1: 数据集的整体统计特征是怎样的?
  • 问题2: 不同性别的用户在收入和投资上有什么差异?

汇总工具1: .describe() - 获取描述性统计

.describe() 方法可以快速计算出所有数值型列的常用统计指标。

df.describe()
income stock stock_income_ratio
count 10.000000 10.000000 10.000000
mean 190603.500000 123253.758925 0.695423
std 89590.564097 86907.971239 0.544712
min 79886.000000 19837.356160 0.136924
25% 145398.750000 53176.251033 0.352543
50% 159634.500000 110580.859385 0.519067
75% 217635.750000 203317.279387 0.881390
max 390838.000000 242928.815258 1.795907

汇总工具2: groupby() - 分组聚合的神器

groupby() 是 Pandas 中最强大的功能之一。它遵循 “拆分-应用-合并” (Split-Apply-Combine) 的思想。

Split-Apply-Combine Diagram An illustration of the groupby mechanism: a table is split into groups, a function is applied to each group, and the results are combined into a new table. Key Data A 1 B 5 A 3 A 2 B 4 DataFrame 拆分 (Split) 1 3 2 5 4 应用 (Apply) sum() 6 9 合并 (Combine) Key Sum A 6 B 9 Result

groupby() 实战:按性别分析收入和投资

问题: 计算男性和女性用户各自的平均收入/投资额、中位数和标准差。

我们可以使用 .agg() 方法一次性应用多个聚合函数。

# 我们想对 'income' 和 'stock' 这两列进行操作
# 我们想计算 'mean', 'median', 'std' 这三个统计量
grouped_stats = df.groupby('gender')[['income', 'stock']].agg(['mean', 'median', 'std'])
print(grouped_stats)
          income                                   stock                 \
            mean    median            std           mean         median   
gender                                                                    
F       199090.6  146958.0  120183.237462  100656.361559   64899.691009   
M       182116.4  162337.0   58612.864725  145851.156290  181397.055782   

                      
                 std  
gender                
F       79680.450713  
M       96791.836696  

步骤7: 数据合并 - 整合多个数据源

在现实世界中,数据往往来自不同的文件或数据库。我们需要将它们整合起来进行统一分析。

场景: 我们有另一份 gpa.csv 文件,包含了用户的大学GPA信息。

合并工具: pd.merge() - 类似SQL的连接操作

pd.merge() 函数可以根据一个或多个共同的键(key)将两个 DataFrame 连接在一起。

# 先读入gpa数据
df_gpa = pd.read_csv('data/gpa.csv')
print('GPA 数据预览:')
print(df_gpa.head(2))

# 按 'id' 列合并两个DataFrame
df_merged = pd.merge(df, df_gpa, on='id')

print('\n合并后的数据预览:')
print(df_merged.head(2))
GPA 数据预览:
    id   gpa
0  i_1  2.37
1  i_2  2.61

合并后的数据预览:
    id  income gender         stock  stock_income_ratio   gpa
0  i_1  146958      F  51658.712279            0.351520  2.37
1  i_2  171867      M  28649.648860            0.166697  2.61

步骤8: 数据存储 - 保存你的分析结果

分析处理完成后,通常需要将最终的干净、完整的数据集保存到硬盘,以备后续使用。

我们将把合并后的 df_merged 保存为一个新的CSV文件。

保存工具: .to_csv()

.to_csv() 方法可以将 DataFrame 写入一个CSV文件。

最佳实践: 设置 index=False,避免将Pandas的行索引写入文件,防止下次读入时多出一列。

df_merged.to_csv('data/merged.csv', index=False)
print('文件 "merged.csv" 已成功保存。')
文件 "merged.csv" 已成功保存。

第四部分:用数据讲故事:可视化探索

实战演练:数据可视化与探索

数字是抽象的,而图形是直观的。数据可视化是理解数据、发现模式、沟通见解的最有效方式。

工具: 我们将主要使用 Seaborn,并用 Matplotlib 进行一些定制。

数据: 我们将使用 Seaborn 自带的 tips 数据集。

步骤0: 准备可视化环境和数据

首先,导入库并加载 tips 数据集。

import seaborn as sns
import matplotlib.pyplot as plt

# 设置一个美观的绘图风格
sns.set_theme(style="whitegrid")

# 加载seaborn自带的tips数据集
tips = sns.load_dataset('tips')

print('Tips 数据集预览:')
tips.head()
Tips 数据集预览:
total_bill tip sex smoker day time size
0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4

可视化任务1: 理解单个变量的分布

研究问题: 小费金额(tip)的分布是怎样的?大多数小费集中在哪个范围?是否存在极端值?

适用图表: 直方图 (Histogram)

直方图:观察数据分布的形状

直方图通过将数据分组成等宽的“箱子”(bins),并统计落在每个箱子内的数据点数量,来展示数据的分布情况。

plt.figure(figsize=(9, 5)) # 设置画布大小
sns.histplot(data=tips, x='tip', kde=True, color='dodgerblue') # 核心绘图代码
plt.title('大多数小费集中在2到4美元之间')
plt.xlabel('小费金额 (美元)')
plt.ylabel('频数')
plt.show()
Figure 1: 小费金额的分布直方图

可视化任务2: 比较不同组别的分布

研究问题: 工作日(周四、周五)和周末(周六、周日)的小费分布有何不同?

适用图表: 箱形图 (Box Plot)

箱形图:简洁地展示五数概括

箱形图(又称盒须图)用一种简洁的方式展示了数据的关键统计特征,对于比较多个组的分布和识别异常值尤其有效。

Anatomy of a Box Plot A diagram explaining the different parts of a box plot: minimum, Q1, median, Q3, maximum, and outliers. 异常值 (Outlier) 最大值 (Maximum) 第三四分位数 (Q3) 中位数 (Median) 第一四分位数 (Q1) 最小值 (Minimum)

绘制箱形图:使用 sns.boxplot()

plt.figure(figsize=(9, 5))
sns.boxplot(data=tips, x='day', y='tip', palette='pastel', order=['Thur', 'Fri', 'Sat', 'Sun'])
plt.title('周末的小费中位数更高且波动更大')
plt.xlabel('星期')
plt.ylabel('小费金额 (美元)')
plt.show()
Figure 2: 按天比较小费金额的箱形图

解读: 从图中可以清晰地看到,周六和周日的小费中位数(箱子中间的线)普遍高于周四和周五。同时,周末也出现了更多的高额小费(异常值点)。

可视化任务3: 比较不同类别的平均值

研究问题: 午餐和晚餐的平均小费有差异吗?

适用图表: 条形图 (Bar Plot)

绘制条形图:使用 sns.barplot()

Seaborn的条形图默认计算的是每个类别的均值,并用误差棒(error bars)表示该均值的95%置信区间。

plt.figure(figsize=(8, 5))
sns.barplot(data=tips, x='time', y='tip', palette='coolwarm')
plt.title('晚餐的平均小费显著高于午餐')
plt.xlabel('用餐时间')
plt.ylabel('平均小费 (美元)')
plt.show()
Figure 3: 按用餐时间比较平均小费

解读: 晚餐的平均小费明显高于午餐,并且它们的置信区间没有重叠,这表明这种差异在统计上可能是显著的。

可视化任务4: 探索两个连续变量的关系

研究问题: 消费总额(total_bill)和小费(tip)之间是否存在关系?关系有多强?

适用图表: 散点图 (Scatter Plot)

绘制散点图:使用 sns.scatterplot()

散点图在二维平面上用点来表示两个数值变量的值,用于揭示变量间的相关性。

plt.figure(figsize=(9, 5))
sns.scatterplot(data=tips, x='total_bill', y='tip', alpha=0.6)
plt.title('消费金额越高,支付的小费也越高')
plt.xlabel('总消费金额 (美元)')
plt.ylabel('小费金额 (美元)')
plt.show()
Figure 4: 总消费金额与小费金额的关系

解读: 图中显示出明显的正相关关系:随着总消费金额的增加,小费金额也呈线性增长趋势。

可视化任务5: 量化多个变量间的关系

研究问题: total_bill, tip, 和 size 这三个数值变量之间的相关性具体是多少?

适用图表: 热图 (Heatmap)

绘制热图:先算相关性,再用 sns.heatmap()

这个过程分两步: 1. 使用 Pandas 的 .corr() 方法计算相关系数矩阵。 2. 将这个矩阵传入 sns.heatmap() 进行可视化。

# 步骤1: 选取数值列并计算相关系数矩阵
corr = tips[['total_bill', 'tip', 'size']].corr()

# 步骤2: 绘制热图
plt.figure(figsize=(8, 5))
sns.heatmap(corr, annot=True, cmap='vlag', center=0, fmt='.2f')
# annot=True 在格子上显示数值
# cmap='vlag' 使用一个在0点发散的色板
# fmt='.2f' 格式化数值为两位小数
plt.title('消费金额、小费和用餐人数之间存在强正相关')
plt.show()
Figure 5: 核心数值变量的相关性热图

解读: 热图量化了我们的观察:total_billtip 的相关系数为0.68,这是一个中等强度的正相关。

课程总结

今天,我们从理论到实践,学习了数据管理与探索的全过程:

数据存储

理解了内存与硬盘的权衡,以及CSV、Parquet等格式的选择。

数据管理 (Pandas)

掌握了数据读写、查询、筛选、聚合、合并等一系列核心操作。

数据探索 (Seaborn)

学会了使用多种图表来发现数据背后的故事和模式。

这些技能是进行任何严肃的金融数据分析的基石

动手实践:课堂练习

理论学习需要通过实践来巩固。请使用我们今天生成的 income_stock.csvgpa.csv 数据,完成以下操作。

练习1-2:数据读入与合并

  1. 读入数据: 读入 income_stock.csv 数据。
  2. 合并数据: 将其与 gpa.csv 数据以用户 id 为键进行合并。

练习1-2参考答案

# 1. 读入数据
df_income = pd.read_csv('data/income_stock.csv')

# 2. 合并数据
df_gpa = pd.read_csv('data/gpa.csv')
df_full = pd.merge(df_income, df_gpa, on='id')

print('合并后的数据帧 df_full 的前5行:')
df_full.head()
合并后的数据帧 df_full 的前5行:
id income gender stock gpa
0 i_1 146958 F 51658.712279 2.37
1 i_2 171867 M 28649.648860 2.61
2 i_3 156932 M 218551.394257 3.05
3 i_4 390838 F 156262.027760 2.86
4 i_5 284178 M 181397.055782 2.58

练习3-4:数据筛选与汇总

  1. 选取子集: 选取所有女性用户的数据,并存入一个新的数据帧。
  2. 数据总结: 对这个新的女性用户数据帧进行总结,计算 income, stock, 和 gpa 的描述性统计信息。

练习3-4参考答案

# 3. 选取女性用户数据
df_female = df_full[df_full['gender'] == 'F'].copy() # 使用 .copy() 避免 SettingWithCopyWarning
print('女性用户数据帧 df_female 的前5行:')
print(df_female.head())

# 4. 对女性用户数据进行总结
print('\n女性用户的统计信息:')
print(df_female[['income', 'stock', 'gpa']].describe())
女性用户数据帧 df_female 的前5行:
    id  income gender          stock   gpa
0  i_1  146958      F   51658.712279  2.37
3  i_4  390838      F  156262.027760  2.86
5  i_6  144879      F   19837.356160  3.22
7  i_8  232892      F  210624.020588  2.58
8  i_9   79886      F   64899.691009  2.73

女性用户的统计信息:
              income          stock       gpa
count       5.000000       5.000000  5.000000
mean   199090.600000  100656.361559  2.752000
std    120183.237462   79680.450713  0.318857
min     79886.000000   19837.356160  2.370000
25%    144879.000000   51658.712279  2.580000
50%    146958.000000   64899.691009  2.730000
75%    232892.000000  156262.027760  2.860000
max    390838.000000  210624.020588  3.220000

练习5:数据存储为Parquet格式

  1. 存为Parquet: 将上一步创建的女性用户数据帧 df_female 存为一个 female_data.parquet 文件。

练习5参考答案

# 为了能够写入parquet,可能需要安装pyarrow库
# pip install pyarrow
try:
    df_female.to_parquet('data/female_data.parquet')
    print('文件 "female_data.parquet" 已成功保存。')
except ImportError:
    print('请先安装 pyarrow 库: pip install pyarrow')
文件 "female_data.parquet" 已成功保存。

练习6:重新读入并可视化关系

  1. 重新读入: 重新读入原始的 income_stock.csv 数据。
  2. 散点图: 使用散点图来可视化 incomestock 之间的关系。

练习6参考答案

df_income_reload = pd.read_csv('data/income_stock.csv')

plt.figure(figsize=(9, 5))
sns.scatterplot(data=df_income_reload, x='income', y='stock')
plt.title('收入与股票投资额关系')
plt.xlabel('收入')
plt.ylabel('股票投资额')
plt.show()
Figure 6: 收入与股票投资关系

练习7:可视化性别差异

  1. 条形图: 使用条形图来可视化和比较男性与女性在平均投资总额 (stock) 上的区别。

练习7参考答案

plt.figure(figsize=(8, 5))
sns.barplot(data=df_full, x='gender', y='stock', palette=['lightblue', 'salmon'])
plt.title('男性与女性的平均股票投资额对比')
plt.xlabel('性别')
plt.ylabel('平均股票投资额')
plt.show()
Figure 7: 男女平均股票投资额对比

练习8:可视化多变量相关性

  1. 热图: 使用热图来可视化 income, stock, 以及 gpa 三个变量之间的相关性。

练习8参考答案

# 首先计算相关性矩阵
corr_matrix_ex = df_full[['income', 'stock', 'gpa']].corr()

# 然后绘制热图
plt.figure(figsize=(8, 5))
sns.heatmap(corr_matrix_ex, annot=True, cmap='coolwarm', center=0, fmt='.2f')
plt.title('收入、股票投资与GPA的相关性热图')
plt.show()
Figure 8: 收入、投资与GPA的相关性