3、Python基础速通(二):列表、字典、元组、集合——量化数据处理的基石

上一章我们聊了变量和基础运算,算是把地基打好了。但做量化交易,你面对的不是一个数字,而是一堆数字——股票池、历史K线、持仓列表、订单簿……这些数据怎么装、怎么查、怎么改?

这就得靠Python的四大容器:列表、字典、元组、集合。说白了,它们就是用来装数据的「箱子」,但每个箱子的用法和脾气都不一样。

我个人习惯,写策略之前,先把这四种结构在脑子里过一遍。选错了容器,后面改代码能改到怀疑人生。

核心要点: 列表管顺序,字典管映射,元组管不变,集合管去重。量化数据处理中,80%的操作都离不开它们。

3.1 列表:你的数据流水线

列表是Python里最常用的容器。它就像一条传送带,数据按顺序排好,你可以随时往里面加东西、取东西、改东西。

创建与基础操作

# 一个简单的股票代码列表
stock_list = ['000001', '600519', '300750', '002415']

# 获取第2个元素(索引从0开始)
print(stock_list[1])  # 输出: 600519

# 切片:取前3个
print(stock_list[:3])  # 输出: ['000001', '600519', '300750']

# 追加新股票
stock_list.append('000002')
print(stock_list)  # 输出: ['000001', '600519', '300750', '002415', '000002']

我在项目中遇到过一个问题:用列表存了1000只股票的日收益率,然后想批量计算移动平均。如果直接用for循环一个个算,速度慢得让人抓狂。后来我改用列表推导式,一行代码搞定。

# 列表推导式:快速生成数据
prices = [100, 102, 101, 105, 108]
# 计算每日收益率(百分比)
returns = [(prices[i] - prices[i-1]) / prices[i-1] * 100 for i in range(1, len(prices))]
print(returns)  # 输出: [2.0, -0.98, 3.96, 2.86]
我的习惯: 处理时间序列数据时,尽量用列表推导式代替for循环。代码更短,执行更快,而且不容易写错索引。

列表的常用方法

方法 作用 量化场景举例
append() 末尾添加元素 实时行情来了,追加到价格列表
extend() 合并另一个列表 把两个时间段的K线数据拼接
sort() 原地排序 按收益率排序,找出最强/最弱股票
index() 查找元素位置 找到某只股票在池子里的索引
注意: sort() 是原地排序,会直接修改原列表。如果你不想改变原数据,用 sorted() 函数,它会返回一个新列表。

3.2 字典:股票代码与数据的「通讯录」

字典存的是键值对。你可以把它想象成一本通讯录:你查「600519」,它告诉你「贵州茅台」和它的当前股价。在量化里,字典最适合做映射关系。

为什么字典在量化中这么重要?

你想想看,如果你有3000只股票,每只股票都有开盘价、收盘价、最高价、最低价、成交量……如果用列表存,你得记住每个字段在第几个位置。用字典就简单了:

# 用字典存储一只股票的关键数据
stock_info = {
    'code': '600519',
    'name': '贵州茅台',
    'close': 1850.00,
    'volume': 3200000,
    'ma5': 1835.50,
    'ma20': 1800.20
}

# 获取收盘价
print(stock_info['close'])  # 输出: 1850.0

# 更新数据
stock_info['close'] = 1860.50
print(stock_info['close'])  # 输出: 1860.5

我曾经犯过一个低级错误:用字典存了全市场股票的实时行情,每次更新时直接赋值。结果跑了一段时间,发现内存暴涨。后来才意识到,字典的键是字符串,每个键都会占用内存。3000只股票,每只股票存10个字段,就是3万个键值对。嗯,这里要注意:字典虽好,但别滥用。

字典的常用操作

# 批量更新多个字段
stock_info.update({'close': 1870.00, 'volume': 3500000})

# 安全取值(不存在时返回默认值)
pe = stock_info.get('pe_ratio', 0)
print(pe)  # 输出: 0(因为字典里没有这个键)

# 遍历字典
for key, value in stock_info.items():
    print(f"{key}: {value}")
避坑指南: 我曾经用 stock_info['pe_ratio'] 直接取值,结果某只股票没有这个字段,程序直接崩溃。从那以后,我养成了用 get() 方法的习惯,至少不会因为一个缺失字段让整个策略停摆。

3.3 元组:不可变的「安全箱」

元组和列表很像,但有一个关键区别:元组一旦创建,就不能修改。你想想看,在量化交易中,有些数据是绝对不能改的——比如交易信号的参数、策略的固定配置、或者某只股票的历史最高价。

# 定义一个交易信号参数
trade_params = (5, 20, 0.02)  # 短周期、长周期、止损比例

# 尝试修改会报错
# trade_params[0] = 10  # TypeError: 'tuple' object does not support item assignment

# 但可以整体替换
trade_params = (10, 30, 0.03)  # 这是合法的

我个人习惯,把策略里那些「写死了」的参数都用元组存。比如均线周期、仓位比例、滑点设置。这样别人改代码时,一眼就能看出哪些是「不能动的」。

元组的解包

# 从数据库查出来的一条记录
record = ('000001', '平安银行', 12.35, 5000000)
code, name, price, volume = record
print(f"{name} 当前价格: {price}")  # 输出: 平安银行 当前价格: 12.35
核心区别: 列表用方括号 [],元组用圆括号 ()。列表可变,元组不可变。量化中,元组常用于函数返回多个值、存储固定配置。

3.4 集合:去重与交集运算的利器

集合,说白了就是一个「不重复的元素集」。在量化里,最常见的场景就是去重和求交集。

场景一:去重

假设你从多个数据源拉取了股票列表,里面可能有重复的代码。用集合去重,一行搞定:

# 多个数据源合并的股票列表(有重复)
raw_list = ['000001', '600519', '000001', '300750', '600519', '002415']
unique_stocks = set(raw_list)
print(unique_stocks)  # 输出: {'000001', '002415', '300750', '600519'}

场景二:求交集

做量化选股时,经常需要找「同时满足多个条件」的股票。比如:既在沪深300成分股里,又满足技术面买入信号。

# 沪深300成分股
hs300 = {'000001', '000002', '600519', '300750', '002415'}
# 技术面选股结果
tech_signals = {'600519', '300750', '000858', '002304'}

# 求交集:同时满足两个条件的股票
final_pool = hs300 & tech_signals
print(final_pool)  # 输出: {'600519', '300750'}
我的经验: 集合的运算速度非常快,比用列表做循环判断快一个数量级。如果你需要做「属于/不属于」「交集/并集」这类操作,优先用集合。

3.5 四种容器的选择指南

说了这么多,到底什么时候用哪个?我总结了一张表,你直接照着用就行:

容器类型 适用场景 量化案例
列表 有序、可变的序列数据 历史K线、收益率序列、订单队列
字典 键值映射、快速查找 股票代码→行情数据、策略参数配置
元组 不可变的固定数据 策略参数、数据库记录、函数多返回值
集合 去重、集合运算 股票池去重、多条件选股交集
最后提醒一句: 别小看这些基础容器。我见过太多人,策略逻辑写得天花乱坠,结果因为选错了数据结构,代码跑起来又慢又容易出错。基础打牢了,后面写策略才能行云流水。
Python四大容器 · 量化数据选型指南 Python容器 列表 [ ] 有序 · 可变 · 可重复 K线序列 · 收益率列表 字典 { } 键值映射 · 快速查找 股票→行情 · 参数配置 元组 ( ) 有序 · 不可变 策略参数 · 数据库记录 集合 { } 无序 · 唯一 · 可运算 去重 · 交集/并集运算 选型口诀:列表管顺序,字典管映射,元保管不变,集合管去重 量化数据处理中,80%的操作都离不开这四种容器
蓝海数据掘金营,专注资料整理