如何在Python中求解含标准差的股票价格不等式?
问题描述
我把过去19天的股票价格存在pd.DataFrame里,想找到满足 P < mean - 2.5*standard deviation 的价格P——这里的均值和标准差是包含P在内的20个数据(过去19天+P)的统计量。尝试用SymPy的solve函数求解时,调用np.std()报错,示例代码和错误信息如下:
from sympy.solvers import solve from sympy import Symbol x = Symbol('x') solve(x-np.mean([1,2,3,x])-np.std([1,2,3,x]), x)
错误信息:
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) AttributeError: 'Add' object has no attribute 'sqrt' The above exception was the direct cause of the following exception: TypeError Traceback (most recent call last) Input In [71], in <cell line: 4>() 2 from sympy import Symbol 3 x = Symbol('x') ----> 4 solve(x-np.mean([1,2,3,x])-np.std([1,2,3,x]), x) File ~/opt/anaconda3/lib/python3.9/site-packages/numpy/core/fromnumeric.py:3645, in std(a, axis, dtype, out, ddof, keepdims, where) 3642 else: 3643 return std(axis=axis, dtype=dtype, out=out, ddof=ddof, **kwargs) -> 3645 return _methods._std(a, axis=axis, dtype=dtype, out=out, ddof=ddof, 3646 **kwargs) File ~/opt/anaconda3/lib/python3.9/site-packages/numpy/core/_methods.py:214, in _std(a, axis, dtype, out, ddof, keepdims, where) 212 ret = ret.dtype.type(um.sqrt(ret)) 213 else: --> 214 ret = um.sqrt(ret) 216 return ret TypeError: loop of ufunc does not support argument 0 of type Add which has no callable sqrt method
解决方法
报错核心原因是numpy的数值计算函数(np.mean、np.std)无法处理SymPy的符号变量,两者定位不同:numpy负责数值运算,SymPy负责符号运算,不能直接混用。下面提供两种可行方案:
方案1:用SymPy原生统计函数替换numpy函数
SymPy自带符号化的均值、标准差计算函数,直接替换numpy的对应函数即可正常求解:
from sympy.solvers import solve from sympy import Symbol, mean, std x = Symbol('x') # 注意sympy的std默认用样本标准差(ddof=1),如果需要总体标准差可以加参数ddof=0 solve(x - mean([1,2,3,x]) - 2.5*std([1,2,3,x]), x)
方案2:代数推导后直接数值计算(更高效)
无需依赖符号计算工具,手动推导不等式的代数形式后直接计算,适合批量处理数据:
假设过去19天价格的总和为S,平方和为SS,加入P后共20个数据:
- 均值
μ = (S + P)/20 - 标准差
σ = sqrt( (SS + P²)/20 - μ² )
将上述式子代入原不等式 P < μ - 2.5σ,整理后可得到关于P的一元二次不等式,直接求解根即可确定P的范围:
import pandas as pd import numpy as np # 假设你的DataFrame是df,价格列名为'price' past_prices = df['price'].tail(19).values S = past_prices.sum() SS = (past_prices ** 2).sum() n = 20 # 19天+P的总数据量 k = 2.5 # 你的标准差倍数 # 整理后的二次不等式系数:a*P² + b*P + c < 0 a = n - k**2 b = -2*S + 2*(k**2)*S / n c = (S**2)/n - (k**2)*(SS - (S**2)/n) # 求解二次方程的根 roots = np.roots([a, b, c]) roots.sort() # 根据二次函数开口方向确定解的区间 if a > 0: # 开口向上,不等式的解为两根之间 valid_P_range = (roots[0], roots[1]) else: # 开口向下,解为两根之外 valid_P_range = (-np.inf, roots[0]), (roots[1], np.inf) print(f"满足条件的P范围:{valid_P_range[0]:.4f} < P < {valid_P_range[1]:.4f}")
内容的提问来源于stack exchange,提问作者Roy Chang
相关产品推荐
相关产品推荐

