使用matplotlib绘制正态分布 郝伟 2020/12/28 [TOC]

1. 简介

相关数学公式

  • 正态分布函数

  • 正态分布函数的概率密度

所实现的绘制效果 image

2. 绘制过程

在scipy空间中也提供了相应的正态分布生成函数, 生成代码如下所示:

# 也可以直接使用scipy生成 
x_min, x_max = 0.0, 100.0
xs = np.linspace(x_min, x_max, 100)
ys = scipy.stats.norm.pdf(xs, mu, sigma)

正态分布的计算公式有两个 pdf 和 cdf

import scipy.stats

# mu(μ, 读作:谬) 数学期望, 
# sigma (σ, 读作:西格玛)标准差
mu,sigma=50,12

# scipy中的正态分布函数的概率密度函数对象
n1 = scipy.stats.norm(mu, sigma)

# 分别打印正态分布函数和其概率密度函数
print('f(50)=', n1.pdf(50), ', F(50)=', n1.cdf(50))  

# 打印正负6个sigma的差值
for i in [1, 2, 3, 4, 5, 6]:
    print(str(i) + 'σ=',  n1.cdf(mu + i * sigma) - n1.cdf(mu - i * sigma))

运行结果

f(50)= 0.03324519003345273 , F(50)= 0.5
1σ= 0.6826894921370859
2σ= 0.9544997361036416
3σ= 0.9973002039367398
4σ= 0.9999366575163338
5σ= 0.9999994266968562
6σ= 0.9999999980268246

3. 源代码

以下是所显示的图片的完整绘制代码


import math
import matplotlib.pyplot as plt
import numpy as np
import scipy.stats 

def normal_dis(x, mu=50, sigma=5):
    '''
    x: 输入待计算的值
    μ: (mu, 读作:谬) 为数学期望, 
    σ (sigma, 读作:西格玛)为标准差
    '''
    # k = 0.3989422804014327 / mu # 1.0 / math.sqrt(2 * math.pi)
    # 其中,0.3989422804014327 = 1/sqrt(2*pi)
    return 0.3989422804014327 / sigma * math.exp(- (x - mu) * (x - mu) / (2 * sigma * sigma))

# pyplot methods reference
# https://matplotlib.org/api/_as_gen/matplotlib.pyplot.html?highlight=plot#module-matplotlib.pyplot 

# 支持中文
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False    # 用来正常显示负号

# mu 和 sigma
mu, sigma = 50, 12
n1 = scipy.stats.norm(mu, sigma)

# 生成符合 N(mu, sigma)的正态分布曲线的数据
# PS: scipy中提供了生成方法,如 ys = scipy.stats.norm.pdf(xs, mu, sigma)
xs = list(range(101))
ys = [normal_dis(x, mu, sigma) for x in xs]
plt.plot(xs, ys, color='darkblue', label='正态分布曲线')

# 填充函数区域
for i in range(1, 4):
    xs = np.linspace(mu - sigma * i, mu + sigma * i, 100)
    ys = scipy.stats.norm.pdf(xs, mu, sigma)
    plt.fill_between(xs, ys, 0, alpha=0.35, color='darkblue')

# 绘制线条和文字
for i in range(1, 4):  
    # 计算中间三个区间连线的两端坐标
    x1 = mu - sigma * i
    x2 = mu + sigma * i
    y1 = normal_dis(x1, mu, sigma)
    y2 = normal_dis(x2, mu, sigma)
    # 绘制三条线段,分别为左右1条和上下2条
    plt.plot([x1, x2], [y1, y2], color='r')
    plt.plot([x1, x1], [y1, 0], color='black')
    plt.plot([x2, x2], [y1, 0], color='black')
    # 绘制相应的文本
    plt.text((x1+x2)/2-3, y1, '{:.2%}'.format(n1.cdf(x2) - n1.cdf(x1)), fontsize=14, color='w')
    plt.text(x1 - 12, y1, f"$\mu - {i}\sigma$", fontsize=14)
    plt.text(x2 + 3, y1, f"$\mu + {i}\sigma$", fontsize=14)

# 绘制顶部横线
y_top = 1/math.sqrt(2*math.pi)/sigma
plt.plot([0, mu], [y_top, y_top], color='black')    

# 绘制最上方的单个的 \mu    
plt.text(mu, normal_dis(mu, mu, sigma) + 0.0003, f'$\mu$', fontsize=14, color='black')  


#用plot函数绘制折线图,线条颜色设置为绿色
plt.title(f'正态分布($\mu=50, \sigma=12$)',fontsize=24)
#设置图表标题和标题字号
plt.tick_params(axis='both',which='major',labelsize=14)
#设置刻度的字号
plt.xlabel('取值范围',fontsize=14)
#设置x轴标签及其字号
plt.ylabel('概率',fontsize=14)

# 设置X轴和Y轴的显示范围
plt.xlim(0, 100)
plt.ylim(0, 0.035)

# 设置X轴的显示的内容为 [0, 10, 20, ..., 100]
plt.xticks(range(0, 110, 10))

# 显示每条曲线的文本
plt.legend()

# 显示网格,黑色透明度为 0.2
plt.grid(color='black', alpha=0.2)

plt.show()

4. 补充

如果需要将以上内容矢量输出至PDF,请参考此文

5. 参考文献

[1] matplotlib 官网, matplotlib.pyplot API文档, https://matplotlib.org/api/_as_gen/matplotlib.pyplot.html?highlight=plot#module-matplotlib.pyplot [2] matplotlib官方, plot函数API文档, https://matplotlib.org/api/_as_gen/matplotlib.pyplot.plot.html [3] 欧德飞, 标准正态分布概率密度函数的定积分计算方法及Python实现代码, https://zhuanlan.zhihu.com/p/59495652

results matching ""

    No results matching ""