问题描述
df = get_valuation(g.stocks, end_date=context.previous_date, count=1, fields=['code', 'circulating_market_cap'])
返回df中code的顺序与传入的list中股票顺序不一样,这是为什么?
解决方案
问题原因
在 JoinQuant(聚宽)平台中,调用 get_valuation 函数获取多只股票的财务/市值数据时,底层实际上是向数据库发起了一次批量查询(类似于 SQL 中的 IN 语句)。
关系型数据库在处理这类批量查询时,默认是不保证返回结果的顺序与传入列表的顺序一致的。数据库会根据其内部的索引和数据存储物理位置来返回数据,以达到最快的查询效率。因此,返回的 Pandas DataFrame 中 code 列的顺序通常是无序的,或者与你传入的 g.stocks 列表顺序不同。
解决方法
如果你需要返回的 DataFrame 严格按照你传入的 g.stocks 列表顺序排列,可以利用 Pandas 强大的数据处理功能对结果进行重排。以下提供两种常用的解决方法:
方法一:使用 set_index 和 loc 进行重排(推荐)
这是最简单直观的方法。将 code 列设置为索引,然后使用你的原始列表进行索引选取,最后再重置索引。
import pandas as pd
# 假设 g.stocks 是你的股票列表
# g.stocks = ['000001.XSHE', '000002.XSHE', '600000.XSHG']
# 1. 获取数据
df = get_valuation(g.stocks, end_date=context.previous_date, count=1, fields=['code', 'circulating_market_cap'])
# 2. 按照 g.stocks 的顺序重排 DataFrame
# 注意:如果 g.stocks 中有某些股票在当天没有数据(如停牌或退市),loc 可能会引入 NaN,可以使用 reindex 避免报错
df_sorted = df.set_index('code').reindex(g.stocks).reset_index()
# 此时 df_sorted 中的顺序已经和 g.stocks 完全一致
print(df_sorted)
方法二:使用 Pandas 的 Categorical 类型进行排序
你可以将 code 列转换为分类数据(Categorical),并指定分类的顺序为你传入的列表顺序,然后调用 sort_values。
import pandas as pd
# 1. 获取数据
df = get_valuation(g.stocks, end_date=context.previous_date, count=1, fields=['code', 'circulating_market_cap'])
# 2. 将 code 列设置为 Categorical 类型,并指定顺序为 g.stocks
df['code'] = pd.Categorical(df['code'], categories=g.stocks, ordered=True)
# 3. 按照 code 列排序并重置索引
df_sorted = df.sort_values('code').reset_index(drop=True)
print(df_sorted)
总结
在量化策略开发中,API 返回的数据顺序不一致是常见现象。养成不依赖 API 默认返回顺序的习惯,并在需要特定顺序时显式地使用 Pandas 进行排序或对齐,可以有效避免策略中出现潜在的逻辑 Bug(如权重错配)Bug。