4、Pandas数据处理(上):Series与DataFrame基础、数据读取与写入、数据索引与选择

做量化研究,说白了就是跟数据打交道。你想想看,没有数据,再牛的策略也是空中楼阁。而Pandas,就是咱们处理这些数据的瑞士军刀。今天这一章,咱们先把最核心的几块骨头啃下来。

4.1 认识Pandas的两大核心:Series与DataFrame

Pandas里就两种数据结构,你记住就行:SeriesDataFrame

  • Series:一维的,像Excel里的一列。有索引,有值。
  • DataFrame:二维的,像整个Excel表格。有行索引,有列名。

我刚开始学的时候,总把DataFrame当成一个高级的二维数组。后来发现不对,它更像一个字典,每列可以有不同的数据类型。嗯,这个理解很重要。

核心区别:Series是单列,DataFrame是多列。DataFrame可以看作是由多个Series拼起来的。

4.1.1 创建Series

import pandas as pd

# 从列表创建
s1 = pd.Series([100, 200, 300, 400])
print(s1)

# 指定索引
s2 = pd.Series([100, 200, 300, 400], index=['a', 'b', 'c', 'd'])
print(s2)

# 从字典创建(键自动变成索引)
s3 = pd.Series({'平安银行': 12.5, '招商银行': 35.2, '兴业银行': 18.7})
print(s3)

我个人习惯用字典创建,因为键名就是索引,一眼就能看出数据含义。你在做回测时,用股票代码做索引,非常直观。

4.1.2 创建DataFrame

import pandas as pd

# 从字典创建(最常用)
data = {
    '股票代码': ['000001', '600036', '601166'],
    '收盘价': [12.5, 35.2, 18.7],
    '成交量': [1000000, 800000, 500000]
}
df = pd.DataFrame(data)
print(df)

# 指定行索引
df.index = ['股票A', '股票B', '股票C']
print(df)

我在项目中遇到过一个问题:从API拉回来的数据,列名全是英文,看着头疼。后来我习惯在创建DataFrame时直接指定中文列名,省得后面再改。

4.2 数据读取与写入

做量化,数据来源无非就几种:CSV文件、Excel文件、数据库、API。Pandas对前两种支持得特别好。

4.2.1 读取CSV文件

# 读取CSV
df = pd.read_csv('stock_data.csv')

# 常用参数
df = pd.read_csv(
    'stock_data.csv',
    encoding='utf-8',        # 编码,中文数据常用utf-8或gbk
    parse_dates=['日期'],     # 自动解析日期列
    index_col='日期',         # 指定日期列为行索引
    dtype={'股票代码': str}   # 指定列数据类型
)

小技巧:股票代码最好指定为字符串类型,否则像'000001'会被读成数字1,前面两个0就丢了。我曾经因为这个bug排查了半天。

4.2.2 读取Excel文件

# 读取Excel
df = pd.read_excel('stock_data.xlsx', sheet_name='Sheet1')

# 读取多个sheet
dfs = pd.read_excel('stock_data.xlsx', sheet_name=None)  # 返回字典
df_sheet1 = dfs['Sheet1']
df_sheet2 = dfs['Sheet2']

4.2.3 写入文件

# 写入CSV
df.to_csv('output.csv', encoding='utf-8-sig', index=False)

# 写入Excel
df.to_excel('output.xlsx', sheet_name='结果', index=False)

注意那个 utf-8-sig,如果你用Excel打开CSV发现中文乱码,八成是编码问题。加个BOM头(utf-8-sig)就能解决。

4.3 数据索引与选择

这部分是Pandas的精髓。你想想看,几千只股票,几年的数据,怎么快速找到你想要的那一行?

4.3.1 基础选择:[] 操作符

# 选择单列(返回Series)
close = df['收盘价']

# 选择多列(返回DataFrame)
subset = df[['股票代码', '收盘价']]

# 选择前5行
head = df[:5]

# 条件选择
high_volume = df[df['成交量'] > 1000000]

说白了,[] 里放列名就是选列,放切片就是选行。但有个坑:df['收盘价'] 返回的是Series,而 df[['收盘价']] 返回的是DataFrame。两者操作方式不一样,你写代码时要注意。

4.3.2 标签索引:loc

loc 是基于标签(行索引名、列名)的索引方式。我个人最喜欢用这个,因为直观。

# 选择单行
row = df.loc['2024-01-01']

# 选择多行
rows = df.loc['2024-01-01':'2024-01-10']

# 选择特定行和列
cell = df.loc['2024-01-01', '收盘价']

# 选择多行多列
subset = df.loc['2024-01-01':'2024-01-05', ['收盘价', '成交量']]

注意:loc的切片是包含两端的。比如 df.loc['2024-01-01':'2024-01-10'] 会包含1月1日和1月10日的数据。这和Python普通的切片不一样,Python切片是不包含右端点的。

4.3.3 位置索引:iloc

iloc 是基于整数位置的索引。跟Python列表的索引方式一样。

# 选择第一行
row = df.iloc[0]

# 选择前3行
rows = df.iloc[:3]

# 选择第一行第一列
cell = df.iloc[0, 0]

# 选择前3行,第1、3列
subset = df.iloc[:3, [0, 2]]

为什么会有两个索引方式?我刚开始也觉得多余。后来发现,loc 适合按日期、股票代码这种有意义的标签来选数据;iloc 适合按位置循环遍历。两者各有用途。

4.3.4 布尔索引

这是量化分析中最常用的技巧。没有之一。

# 筛选涨幅超过5%的股票
df[df['涨跌幅'] > 0.05]

# 多条件筛选
df[(df['涨跌幅'] > 0.05) & (df['成交量'] > 1000000)]

# 使用isin筛选
codes = ['000001', '600036']
df[df['股票代码'].isin(codes)]

注意多条件时,每个条件要用括号括起来,用 &(与)、|(或)连接。不能用 andor。这个坑我踩过好几次。

4.4 本章知识体系

下面这张图,帮你把本章的核心逻辑串起来:

Pandas数据处理(上)知识体系 Pandas核心 数据结构 Series DataFrame 数据读写 read_csv read_excel to_csv/to_excel 索引与选择 loc(标签) iloc(位置) 布尔索引 核心:掌握数据结构 → 熟练读写 → 灵活索引

这张图把本章的三个核心模块串起来了。你学完这一章,应该能做到:看到数据,知道该用Series还是DataFrame存;拿到文件,知道怎么读进来;读进来之后,知道怎么快速找到你要的数据。

我的建议:别死记硬背API。打开Jupyter Notebook,拿一份真实的股票数据,边练边查。用多了自然就记住了。我当年就是这么过来的。


专注资料整理