首页 > 解决方案 > 无法在 sympy 中整合简单的正态分布,取决于均值和偏差常数

问题描述

所以......我可以sympy.integrate使用均值和标准差进行正态分布:

    (10.1, 0.333333333),  # Works fine

但不是:

    (8.655555555555557, 0.5212875796916135), # Fails

种类感觉应该不会有很大的不同。那是怎么回事?

完整示例:

import numpy as np
%matplotlib inline
import sympy
from sympy import symbols
from sympy import plot

def normal(x, mean, sigma):
    z = (x - mean) / sigma
    return (1 / (sigma * sympy.sqrt(2 * sympy.pi))) * sympy.exp(-(z * z) / 2)


for μ,σ in [
    (10.1, 0.333333333),  # Works fine
    (8.655555555555557, 0.5212875796916135), # Fails
]:
    x = symbols("x")

    print(f"μ={μ}, σ={σ}")
    distrib = normal(x=x,mean=μ,sigma=σ)
    # distrib = sympy.simplify(distrib) # Doesn't help
    distrib_cum = sympy.integrate(distrib, x)
    # distrib_cum = sympy.simplify(distrib_cum) # Doesn't help
    print(distrib_cum)
    plot(distrib_cum)
NameError                                 Traceback (most recent call last)

<ipython-input-18-e85bdeabeaa6> in <module>
     22     # distrib_cum = sympy.simplify(distrib_cum) # Doesn't help
     23     print(distrib_cum)
---> 24     plot(distrib_cum)
     25 
     26 

~/venv/p37_default/lib/python3.7/site-packages/sympy/plotting/plot.py in plot(show, *args, **kwargs)
   1738     plots = Plot(*series, **kwargs)
   1739     if show:
-> 1740         plots.show()
   1741     return plots
   1742 

~/venv/p37_default/lib/python3.7/site-packages/sympy/plotting/plot.py in show(self)
    220             self._backend.close()
    221         self._backend = self.backend(self)
--> 222         self._backend.show()
    223 
    224     def save(self, path):

~/venv/p37_default/lib/python3.7/site-packages/sympy/plotting/plot.py in show(self)
   1414 
   1415     def show(self):
-> 1416         self.process_series()
   1417         #TODO after fixing https://github.com/ipython/ipython/issues/1255
   1418         # you can uncomment the next line and remove the pyplot.show() call

~/venv/p37_default/lib/python3.7/site-packages/sympy/plotting/plot.py in process_series(self)
   1411             if isinstance(self.parent, PlotGrid):
   1412                 parent = self.parent.args[i]
-> 1413             self._process_series(series, ax, parent)
   1414 
   1415     def show(self):

~/venv/p37_default/lib/python3.7/site-packages/sympy/plotting/plot.py in _process_series(self, series, ax, parent)
   1239             # Create the collections
   1240             if s.is_2Dline:
-> 1241                 collection = self.LineCollection(s.get_segments())
   1242                 ax.add_collection(collection)
   1243             elif s.is_contour:

~/venv/p37_default/lib/python3.7/site-packages/sympy/plotting/plot.py in get_segments(self)
    704                     list_segments.append([p, q])
    705 
--> 706             f_start = f(self.start)
    707             f_end = f(self.end)
    708             sample(np.array([self.start, f_start]),

~/venv/p37_default/lib/python3.7/site-packages/sympy/plotting/experimental_lambdify.py in __call__(self, args)
    173         try:
    174             #The result can be sympy.Float. Hence wrap it with complex type.
--> 175             result = complex(self.lambda_func(args))
    176             if abs(result.imag) > 1e-7 * abs(result):
    177                 return None

~/venv/p37_default/lib/python3.7/site-packages/sympy/plotting/experimental_lambdify.py in __call__(self, *args, **kwargs)
    270 
    271     def __call__(self, *args, **kwargs):
--> 272         return self.lambda_func(*args, **kwargs)
    273 
    274 

<string> in <lambda>(x0)

NameError: name 'Integral' is not defined

第一个问题:

μ=10.1, σ=0.333333333
0.353553390593274*sqrt(2)*erf(2.12132034568096*x - 21.4253354913777)

工作正常。

第二:

μ=8.655555555555557, σ=0.5212875796916135
1.30203374788369e-60*sqrt(2)*Integral(exp(31.8522556903367*x)*exp(-1.83998909636091*x**2), x)/sqrt(pi)

绘制时失败并显示“名称错误:名称“积分”未定义”。

(而且我有点怀疑1.30203374788369e-60* ....结局是否会很好)。

截至今天最新的 pip 安装失败(python 3.7,sympy 1.18)。

我的错误或同情的限制?

标签: pythonsympy

解决方案


这是一个有效的案例:

In [125]: normal(x, 8.6, 0.5)
Out[125]: 
                                         2
        -147.92⋅(0.116279069767442⋅x - 1) 
1.0⋅√2⋅ℯ                                  
──────────────────────────────────────────
                    √π                    

In [126]: integrate(_,x)
Out[126]: 0.353553390593274⋅√2⋅erf(1.41421356237309⋅x - 12.1622366364086)

而一个没有:

In [127]: normal(x, 8.655555555555557, 0.5212875796916135)
Out[127]: 
                                                                2
                     -137.849484348735⋅(0.115532734274711⋅x - 1) 
0.95916346270094⋅√2⋅ℯ                                            
─────────────────────────────────────────────────────────────────
                                √π                               

In [128]: integrate(_,x)
Out[128]: 
                        ⌠                                             
                        ⎮                                         2   
                        ⎮  31.8522556903367⋅x  -1.83998909636091⋅x    
1.30203374788369e-60⋅√2⋅⎮ ℯ                  ⋅ℯ                     dx
                        ⌡                                             
──────────────────────────────────────────────────────────────────────
                                  √π                                  

我不知道为什么会有差异。有时在sympy某些情况下我们需要为符号添加约束,例如realor positive。看起来它未能将积分减少到erf. 我想知道是否存在erf定义有效的值范围。我已经很多年没有和它一起工作了。

正如您所注意到的,领先1.30203374788369e-60是可疑的,尤其是与工作案例中的 1 相比。

从 sigma 中删除几个数字使其工作:0.52128757969161


推荐阅读