使用Quantstats utils.make_index()时遇TypeError:float与str无法相加
Quantstats make_index() 触发 TypeError 问题分析
问题现象
调用quantstats.utils.make_index()函数时,触发TypeError: unsupported operand type(s) for +: 'float' and 'str'错误,测试其他标的组合、直接传入标的与权重参数、在旧版本中测试均会复现。
测试代码:
import quantstats as qs qs.extend_pandas() IAC = {"SPY": 1.3, "AGG": -.3} portfolio = qs.utils.make_index(IAC)
报错回溯
Traceback (most recent call last): File "C:\Users\whohe\PycharmProjects\pythonProject\quantstat_portfolio.py", line 31, in <module> portfolio = qs.utils.make_index(IAC,rebalance='1M',period='max',returns=None,match_dates=False) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\quantstats\utils.py", line 400, in make_index return index[index.index <= last_day].sum(axis=1) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\pandas\core\frame.py", line 11670, in sum result = super().sum(axis, skipna, numeric_only, min_count, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\pandas\core\generic.py", line 12506, in sum return self._min_count_stat_function( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\pandas\core\generic.py", line 12489, in _min_count_stat_function return self._reduce( ^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\pandas\core\frame.py", line 11562, in _reduce res = df._mgr.reduce(blk_func) ^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\pandas\core\internals\managers.py", line 1500, in reduce nbs = blk.reduce(func) ^^^^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\pandas\core\internals\blocks.py", line 404, in reduce result = func(self.values) ^^^^^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\pandas\core\frame.py", line 11481, in blk_func return op(values, axis=axis, skipna=skipna, **kwds) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\pandas\core\nanops.py", line 85, in _f return f(*args, **kwargs) ^^^^^^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\pandas\core\nanops.py", line 404, in new_func result = func(values, axis=axis, skipna=skipna, mask=mask, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\pandas\core\nanops.py", line 477, in newfunc return func(values, axis=axis, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\pandas\core\nanops.py", line 646, in nansum the_sum = values.sum(axis, dtype=dtype_sum) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\whohe\PycharmProjects\pythonProject\venv\Lib\site-packages\numpy\core\_methods.py", line 49, in _sum return umr_sum(a, axis, dtype, out, keepdims, initial, where) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: unsupported operand type(s) for +: 'float' and 'str'
问题原因
这个问题是Quantstats包内部的bug,和你的代码无关。
从报错栈可以定位到错误发生在quantstats/utils.py第400行的sum(axis=1)操作——说明函数构建的index数据框中混合了浮点数和字符串类型的数据,导致求和时出现类型不兼容的问题。
根源是make_index()函数在拉取标的数据、计算权重后的收益过程中,没有正确校验并确保所有列都是数值类型,可能是数据拉取时混入了非数值的异常值,或者是某一步数据转换遗漏了类型处理。
临时解决方法
方法1:手动计算组合指数
自己拉取标的收益率并转换为数值类型,手动计算组合收益后转成指数:
import quantstats as qs import pandas as pd qs.extend_pandas() # 拉取标的收益率并强制转为float类型 spy_returns = qs.utils.get_returns("SPY").astype(float) agg_returns = qs.utils.get_returns("AGG").astype(float) # 计算组合加权收益率 portfolio_returns = spy_returns * 1.3 + agg_returns * (-0.3) # 转换为指数形式 portfolio_index = qs.utils.to_index(portfolio_returns)
方法2:修改Quantstats源码
找到你的虚拟环境中quantstats/utils.py文件,定位到make_index函数的第400行附近,在sum(axis=1)之前添加一行代码强制转换所有列为数值类型:
# 在 return index[index.index <= last_day].sum(axis=1) 之前添加 index = index.astype(float) return index[index.index <= last_day].sum(axis=1)
内容的提问来源于stack exchange,提问作者Sávio Coelho
相关产品推荐
相关产品推荐

