累积正态分布函数的逼近

累积正态分布函数的逼近

这篇博客里面的程序主要是根据这篇论文里面对于累积正态分布函数的逼近函数的介绍编写的:累积正态分布函数的逼近函数综述_王晶晶.pdf。根据文中的介绍,我编写了以下 Python 函数实现,并展示了计算的效果。
cnd.py

Fisher z 变换

1915 年,Fisher 提出了一个显式初等函数——Fisher z 变换,根据这一变换可以使用下面的函数近似累积正态分布函数:

$$
Q(x) = \frac{1}{2} \left[ 1 + \frac{e^{2x}-1}{e^{2x}+1} \right]
$$

当$x \approx \pm 0.731693636946$时,Fisher z 变换逼近正态分布分布累积正态分布函数$\Phi(x)$的绝对误差值$max|Q(x)-\Phi(x)|$=0.0442279904503。Fisher z 变换被国内外教材普遍使用。

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def fisher_z(X):
"""
基于1915年Fisher提出的显式初等函数——Fisher z变换逼近累积正态分布函数
当x = +-0.731693636946时,绝对误差为0.0442279904503
:param X: 负无穷到正无穷取值
:return: 累积正态分布积分值的近似
"""
from math import exp
return 0.5*(1+(exp(2*X)-1)/(exp(2*X)+1))
# 测试
fisher_z(1.647)
Out[2]: 0.9642224008919484
fisher_z(-2.3229)
Out[3]: 0.009510526507728212

Page 的初等显式逼近函数

1977 年 Page 提出了如下形式的逼近函数:
$$
Q(x) = 1 - \frac{1}{1+e^{\alpha_{1}x^3+\alpha_2x}}
$$
其中$\alpha_1 = 0.070565992$,$\alpha_2 = 1.5976$。该逼近函数的绝对误差$max|Q(x)-\Phi(x)| < 1.4 \times 10^{-4}$。

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def page(X):
"""
基于1977年Page提出的初等显式函数逼近累积正态分布函数
绝对误差小于1.4e-4
:param X: 负无穷到正无穷取值
:return: 累积正态分布积分值的近似
"""
from math import exp
(a1, a2) = (0.070565992, 1.5976)
return (1 - 1/(1+exp(a1*pow(X, 3)+a2*X)))

page(1.647)
Out[4]: 0.9500984030152408
page(-2.3229)
Out[5]: 0.00999581213376477

Hamaker 逼近函数

1978 年 Hamaker 提出了如下形式的逼近函数:
$$
Q(x) = \frac{1}{2}\left[ 1+{ 1-e^{-(0.806x(1-0.018x))^2} }^{\frac{1}{2}} \right]
$$
当$0 \leq x \leq 4$时,其绝对误差$max|Q(x)-\Phi(x)| < 0.005$。

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def hamaker(K):
"""
基于1978年Hamaker提出的逼近函数近似累积正态分布函数
当x in [-4, 4]时,绝对误差小于0.005
:param X: 负无穷到正无穷取值
:return: 累积正态分布积分值的近似
"""
from math import exp
if (K < -4) | (K > 4) :
print("请输入一个[-4, 4]范围的数!")
else:
X = abs(K)
cnd = 0.5*(1+pow((1-exp(-(0.806*X*(1-0.018*X))**2)),0.5))
if K < 0:
cnd = 1-cnd
return cnd
hamaker(1.647)
Out[6]: 0.949922943335866
hamaker(-2.3229)
Out[7]: 0.010107486681394606
hamaker(5)
请输入一个[-4, 4]范围的数!

Lin 逼近函数

1990 年 Lin 提出了如下逼近函数:
$$
Q(x) = 1 - \frac{1}{1+e^{4.2 \pi x/(9-x)}}
$$
当$0 \leq x < 9$时,其绝对误差$max|Q(x)-\Phi(x)| < 6.8 \times 10^{-3}$。

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def lin(K):
"""
基于1990年Lin提出的逼近函数近似累积正态分布函数
当x in (-9, 9)时,绝对误差小于6.8e-3
:param X: 负无穷到正无穷取值
:return: 累积正态分布积分值的近似
"""
if (K <= -9) | (K >= 9):
print("请输入一个(-9, 9)范围的数!")
else:
X = abs(K)
from math import exp, pi
cnd = (1 - 1/(1+exp(4.2*pi*X/(9-X))))
if K < 0:
cnd = 1 - cnd
return cnd
lin(1.647)
Out[9]: 0.9505219052861956
lin(-2.3229)
Out[10]: 0.010047752984580716
lin(10)
请输入一个(-9, 9)范围的数!

Waissi&Rossin 逼近函数

1996 年 Waissi 和 Rossin 提出了如下逼近函数:
$$
Q(x) = \frac{1}{1+e^{-sqrt{pi}(\beta_{1} x^5 + \beta_{2} x^3 + \beta_{3} x)}}
$$
其中$\beta_1 = -0.0004406, \beta_2 = 0.0418198, \beta_3 = 0.9000000$。当$-8 < x < 8$时,其绝对误差$max|Q(x)-\Phi(x)| < 4.31 \times 10^{-5}$。

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def waissi_rossin(K):
"""
基于1996年Waissi和Rossin提出的逼近函数近似累积正态分布函数
当x in (-8, 8)时,绝对误差小于4.31e-5
:param X: 负无穷到正无穷取值
:return: 累积正态分布积分值的近似
"""
if (K <= -8) | (K >= 8):
print("请输入一个(-9, 9)范围的数")
else:
X = K
from math import exp, sqrt, pi
(b1, b2, b3) = (-0.0004406, 0.0418198, 0.9000000)
return 1/(1+exp(-sqrt(pi)*(b1*pow(X, 5) + b2*pow(X, 3) + b3*X)))
waissi_rossin(1.647)
Out[12]: 0.9502163899334307
waissi_rossin(-2.3299)
Out[13]: 0.009946351796991503

Bryc 一致逼近函数

2002 年 Bryc 提出了一致逼近函数,并进一步提出了一个更精确的逼近函数

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def bryc(K):
"""
基于2002年Bryc提出的一致逼近函数近似累积正态分布函数
绝对误差小于1.9e-5
:param X: 负无穷到正无穷取值
:return: 累积正态分布积分值的近似
"""
X = abs(K)
from math import exp, pi, sqrt
cnd = 1.-(X*X + 5.575192*X + 12.77436324) * exp(-X*X/2.)/(sqrt(2.*pi)*pow(X, 3) + 14.38718147*pow(X, 2) + 31.53531977*X + 2*12.77436324)
if K < 0:
cnd = 1. - cnd
return cnd
bryc(1.647)
Out[14]: 0.9502393005443269
bryc(0)
Out[15]: 0.5
bryc(-2.3229)
Out[16]: 0.010083257461691364

Aludaat&Alodat 逼近函数

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def aludaat_alodat(X):
"""
基于Aludaat和Alodat在2008年提出的逼近函数近似累积正态分布函数
绝对误差小于0.00197323
:param X: 负无穷到正无穷取值
:return: 累积正态分布积分值的近似
"""
from math import pi, sqrt, exp
K = abs(X)
cnd = 0.5*(1+pow((1-exp(-sqrt(pi/8)*K*K)), 0.5))
if X < 0:
cnd = 1 - cnd
return cnd
aludaat_alodat(1.647)
Out[17]: 0.9520215010093231
aludaat_alodat(-2.3229)
Out[18]: 0.008573835188765422

杨正瓴逼近函数

$$
Q(x) = \frac{1}{1+e^{-kx}}
$$
当$k = 1.70174454109$时,其绝对误差小于 0.00945722832868。

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
def yang(X):
"""
基于杨正瓴在2013年提出的Sigmoid-like形式的逼近函数近似累积正态分布函数
绝对误差小于0.00945722832868
:param X: 负无穷到正无穷取值
:return: 累积正态分布积分值的近似
"""
from math import exp
return 1/(1+exp(-1.70174454109*X))
yang(1.647)
Out[19]: 0.9428255019500328
yang(-2.3229)
Out[20]: 0.018835765198913747

CND

最后《Python for Finance》书里面提到了另外一种方法,看起来似乎是使用泰勒展开式近似的方法。

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def CND(X):
"""
计算累积正态分布函数
:param X: 负无穷到正无穷取值
:return: 累积正态分布积分值的近似
"""
from math import sqrt, exp, pi
(a1, a2, a3, a4, a5) = (0.31938153, -0.356563782, 1.781477937, -1.821255978, 1.330274429)
L = abs(X)
K = 1.0/(1.0+0.2316419*L)
w = 1.0 - 1.0/sqrt(2*pi)*exp(-L*L/2.)*(a1*K+a2*K*K+a3*pow(K,3)+a4*pow(K,4)+a5*pow(K,5))
if X < 0:
w = 1.0 - w
return w
CND(1.647)
Out[21]: 0.9502209933627817
CND(-2.3229)
Out[22]: 0.010092238515047591

Excel 函数计算的结果

Excel 中计算累积正态分布的函数是 NORMDIST(x,mean,st,cummulative)。

1
2
3
NORMDIST(0,0,1,1) = 0.5
NORMDIST(-2.3229,0,1,1) = 0.010092263
NORMDIST(1.647,0,1,1) = 0.950220977

封面图片绘制的 Stata 代码

1
2
3
4
tw function normal(x), range(-3 3) || ///
function 1/(1+exp(-1.70174454109*x)), lc(red*0.6) range(-3 3) || ///
function 0.5*(1+(exp(2*x)-1)/(exp(2*x)+1)), lc(red*0.6) range(-3 3) || ///
, leg(order(1 "累积正态分布函数" 2 "杨正瓴逼近函数" 3 "Fisher z变换") pos(6) row(1))
# Python

评论

程振兴

程振兴 @czxa.top
截止今天,我已经在本博客上写了570.7k个字了!

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×