问题描述
neutralize函数报错,pandas版本更新了?_get_fundamental_data函数中funds = pd.Panel(fund_dict)报错
解决方案
问题分析:为什么会出现 pd.Panel 报错?
在 JoinQuant(聚宽)平台或本地使用 jqdatasdk 时,如果您遇到涉及 pd.Panel 的报错(如 AttributeError: module 'pandas' has no attribute 'Panel'),这确实是因为 Pandas 版本更新 导致的。
从 Pandas 0.25.0 版本开始,Panel 数据结构已经被彻底移除。官方建议使用带有 MultiIndex(多重索引)的 DataFrame 或 xarray 来替代三维数据结构。
解决方案
针对您提到的 neutralize 函数报错以及 _get_fundamental_data 中 funds = pd.Panel(fund_dict) 的问题,请按照以下步骤进行修改:
1. 修改自定义函数中的 pd.Panel
如果您在自定义的 _get_fundamental_data 函数中使用了 pd.Panel(fund_dict),需要将其替换为 pd.concat 生成带有 MultiIndex 的 DataFrame,或者直接使用字典推导式处理。
修改前(会报错):
import pandas as pd
# 假设 fund_dict 是一个字典,key 为日期或股票代码,value 为 DataFrame
funds = pd.Panel(fund_dict)
修改后(推荐做法):
import pandas as pd
# 使用 pd.concat 将字典转换为带有 MultiIndex 的 DataFrame
funds = pd.concat(fund_dict, axis=0)
# 或者根据您的具体需求,调整 axis 参数
2. 调整 JoinQuant API 的 panel 参数
如果您调用了 JoinQuant 的官方 API(如 get_price 或 get_fundamentals_continuously),默认情况下它们在旧版本中可能会返回 Panel 对象。您需要显式地将 panel 参数设置为 False。
示例:获取连续财务数据
# 错误写法(在 pandas>=0.25 环境下会报错)
# df = get_fundamentals_continuously(q, end_date='2023-01-01', count=5, panel=True)
# 正确写法:设置 panel=False,返回等效的 DataFrame
df = get_fundamentals_continuously(q, end_date='2023-01-01', count=5, panel=False)
示例:获取多只股票的行情数据
# 正确写法:设置 panel=False
price_df = get_price(['000001.XSHE', '000002.XSHE'], start_date='2023-01-01', end_date='2023-01-10', panel=False)
3. 确保 neutralize 函数的输入格式正确
JoinQuant 的 neutralize(series, how=None, date=None, axis=1) 函数要求传入的 data 参数必须是 pd.Series 或 pd.DataFrame。如果您之前传入的是从 Panel 中提取的数据,请确保在移除 Panel 后,传入的数据结构依然是二维的 DataFrame 或一维的 Series。
正确调用 neutralize 的示例:
from jqfactor import neutralize
import pandas as pd
# 假设 data 是一个 DataFrame,index 为股票代码,columns 为因子值
# 数据中性化处理,按聚宽一级行业和市值进行中性化
neutralized_data = neutralize(data, how=['jq_l1', 'market_cap'], date='2023-01-10', axis=1)
总结
遇到此类问题,核心思路是全面排查代码中所有使用到 pd.Panel 的地方,以及调用聚宽 API 时未设置 panel=False 的地方。将其统一替换为 DataFrame 结构,即可完美兼容新版 Pandas 并解决 neutralize 等函数的连锁报错。