使用Matplotlib在Python中计算和绘制累积分布函数的全面指南
参考:How to calculate and plot a Cumulative Distribution function with Matplotlib in Python
累积分布函数(Cumulative Distribution Function,简称CDF)是概率论和统计学中的一个重要概念,它描述了随机变量小于或等于某个值的概率。在数据分析和可视化中,CDF是一个强大的工具,可以帮助我们理解数据的分布特征。本文将详细介绍如何使用Python的Matplotlib库来计算和绘制CDF,并提供多个实用示例。
1. 累积分布函数的基本概念
累积分布函数F(x)定义为随机变量X小于或等于x的概率:
F(x) = P(X ≤ x)
CDF具有以下特性:
– 单调递增
– 右连续
– 取值范围为[0, 1]
– 当x趋向负无穷时,F(x)趋向0;当x趋向正无穷时,F(x)趋向1
了解这些特性对于正确解释和使用CDF图表至关重要。
2. 准备工作:导入必要的库
在开始绘制CDF之前,我们需要导入必要的Python库。主要使用的库包括NumPy(用于数值计算)和Matplotlib(用于绘图)。
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
print("Welcome to how2matplotlib.com")
这段代码导入了所需的库,并设置了随机种子以确保结果的可重现性。
3. 生成示例数据
为了演示CDF的计算和绘制,我们需要一些示例数据。让我们生成一些随机数据:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
# 生成正态分布的随机数据
data = np.random.normal(loc=0, scale=1, size=1000)
print("Data from how2matplotlib.com:", data[:5])
这段代码生成了1000个服从标准正态分布(均值为0,标准差为1)的随机数。
4. 计算累积分布函数
计算CDF的一种简单方法是使用NumPy的cumsum
和sort
函数:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
def calculate_cdf(data):
sorted_data = np.sort(data)
y = np.arange(1, len(data) + 1) / len(data)
return sorted_data, y
x, y = calculate_cdf(data)
print("CDF data from how2matplotlib.com:")
print("x:", x[:5])
print("y:", y[:5])
这个函数首先对数据进行排序,然后计算每个数据点对应的累积概率。返回的x
是排序后的数据,y
是对应的累积概率。
5. 使用Matplotlib绘制基本的CDF图
现在我们有了CDF的数据,可以使用Matplotlib来绘制图表:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
plt.figure(figsize=(10, 6))
plt.plot(x, y, label='CDF')
plt.title('Cumulative Distribution Function')
plt.xlabel('Value')
plt.ylabel('Cumulative Probability')
plt.legend()
plt.grid(True)
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
这段代码创建了一个基本的CDF图。我们设置了图表的大小、标题、坐标轴标签,并添加了图例和网格线。
6. 美化CDF图表
为了使CDF图表更加美观和信息丰富,我们可以添加一些额外的元素:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
plt.figure(figsize=(12, 7))
plt.plot(x, y, 'b-', linewidth=2, label='CDF')
plt.fill_between(x, y, alpha=0.1)
plt.title('Enhanced Cumulative Distribution Function', fontsize=16)
plt.xlabel('Value', fontsize=12)
plt.ylabel('Cumulative Probability', fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, linestyle='--', alpha=0.7)
plt.xlim(min(x), max(x))
plt.ylim(0, 1)
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
这个增强版的CDF图添加了填充区域、调整了线条宽度、字体大小,并设置了x轴和y轴的范围。
7. 比较多个分布的CDF
在实际应用中,我们经常需要比较不同分布的CDF。让我们生成三个不同的正态分布并比较它们的CDF:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(1, 1.5, 1000)
data3 = np.random.normal(-1, 0.5, 1000)
x1, y1 = calculate_cdf(data1)
x2, y2 = calculate_cdf(data2)
x3, y3 = calculate_cdf(data3)
plt.figure(figsize=(12, 7))
plt.plot(x1, y1, 'b-', label='Distribution 1')
plt.plot(x2, y2, 'r-', label='Distribution 2')
plt.plot(x3, y3, 'g-', label='Distribution 3')
plt.title('Comparison of CDFs for Different Distributions', fontsize=16)
plt.xlabel('Value', fontsize=12)
plt.ylabel('Cumulative Probability', fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, linestyle='--', alpha=0.7)
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
这段代码生成了三个不同参数的正态分布,计算它们的CDF,并在同一图表上绘制,便于比较。
8. 添加参考线和注释
为了更好地解释CDF图,我们可以添加参考线和注释:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
plt.figure(figsize=(12, 7))
plt.plot(x, y, 'b-', linewidth=2, label='CDF')
plt.axhline(y=0.5, color='r', linestyle='--', label='Median')
plt.axvline(x=np.median(data), color='g', linestyle='--', label='Median Value')
plt.title('CDF with Reference Lines', fontsize=16)
plt.xlabel('Value', fontsize=12)
plt.ylabel('Cumulative Probability', fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, linestyle='--', alpha=0.7)
plt.annotate('50% of data\nbelow this point', xy=(np.median(data), 0.5), xytext=(np.median(data)-2, 0.7),
arrowprops=dict(facecolor='black', shrink=0.05))
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
这个示例添加了表示中位数的水平和垂直参考线,并用箭头注释标注了中位数的位置。
9. 使用阶梯图表示离散CDF
对于离散数据,使用阶梯图来表示CDF可能更合适:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
discrete_data = np.random.randint(1, 7, 1000) # 模拟骰子投掷
x, y = calculate_cdf(discrete_data)
plt.figure(figsize=(12, 7))
plt.step(x, y, where='post', label='Discrete CDF')
plt.title('Discrete Cumulative Distribution Function', fontsize=16)
plt.xlabel('Value', fontsize=12)
plt.ylabel('Cumulative Probability', fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, linestyle='--', alpha=0.7)
plt.xticks(range(1, 7))
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
这个例子模拟了骰子投掷的结果,并使用阶梯图来表示离散CDF。
10. 绘制理论CDF与经验CDF的对比
在许多情况下,我们想要比较数据的经验CDF与理论CDF:
from scipy import stats
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
# 生成正态分布数据
data = np.random.normal(0, 1, 1000)
# 计算经验CDF
x_emp, y_emp = calculate_cdf(data)
# 计算理论CDF
x_theo = np.linspace(min(data), max(data), 100)
y_theo = stats.norm.cdf(x_theo, 0, 1)
plt.figure(figsize=(12, 7))
plt.plot(x_emp, y_emp, 'b-', label='Empirical CDF')
plt.plot(x_theo, y_theo, 'r--', label='Theoretical CDF')
plt.title('Empirical vs Theoretical CDF', fontsize=16)
plt.xlabel('Value', fontsize=12)
plt.ylabel('Cumulative Probability', fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, linestyle='--', alpha=0.7)
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
这个示例比较了生成的正态分布数据的经验CDF与理论CDF。
11. 使用子图比较多个CDF
当需要比较多个CDF时,使用子图可以提高可读性:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.exponential(1, 1000)
data3 = np.random.uniform(-2, 2, 1000)
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(18, 6))
for ax, data, title in zip([ax1, ax2, ax3], [data1, data2, data3], ['Normal', 'Exponential', 'Uniform']):
x, y = calculate_cdf(data)
ax.plot(x, y)
ax.set_title(f'{title} Distribution CDF')
ax.set_xlabel('Value')
ax.set_ylabel('Cumulative Probability')
ax.grid(True)
ax.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=ax.transAxes, alpha=0.2, fontsize=20)
plt.tight_layout()
plt.show()
这个例子创建了三个子图,分别显示正态分布、指数分布和均匀分布的CDF。
12. 添加置信区间
在某些应用中,添加置信区间可以提供额外的信息:
from scipy import stats
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
data = np.random.normal(0, 1, 1000)
x, y = calculate_cdf(data)
# 计算95%置信区间
ci = 0.95
n = len(data)
lower = y - 1.96 * np.sqrt(y * (1 - y) / n)
upper = y + 1.96 * np.sqrt(y * (1 - y) / n)
plt.figure(figsize=(12, 7))
plt.plot(x, y, 'b-', label='CDF')
plt.fill_between(x, lower, upper, alpha=0.2, label='95% CI')
plt.title('CDF with 95% Confidence Interval', fontsize=16)
plt.xlabel('Value', fontsize=12)
plt.ylabel('Cumulative Probability', fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, linestyle='--', alpha=0.7)
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
这个示例计算并绘制了CDF的95%置信区间。
13. 使用对数刻度
对于跨越多个数量级的数据,使用对数刻度可能更合适:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
data = np.random.lognormal(0, 1, 1000)
x, y = calculate_cdf(data)
plt.figure(figsize=(12, 7))
plt.semilogx(x, y, 'b-', label='CDF')
plt.title('CDF with Logarithmic X-axis', fontsize=16)
plt.xlabel('Value (log scale)', fontsize=12)
plt.ylabel('Cumulative Probability', fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, linestyle='--', alpha=0.7)
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
这个例子使用对数正态分布的数据,并在x轴使用对数刻度。
14. 绘制反向CDF(生存函数)
生存函数是CDF的补集,在某些领域(如可靠性分析)中很有用:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
data = np.random.exponential(1, 1000)
x, y = calculate_cdf(data)
plt.figure(figsize=(12, 7))
plt.plot(x, 1 - y, 'b-', label='Survival Function')
plt.title('Survival Function (1 - CDF)', fontsize=16)plt.xlabel('Value', fontsize=12)
plt.ylabel('Survival Probability', fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, linestyle='--', alpha=0.7)
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
这个示例绘制了生存函数,它是CDF的补集(1 – CDF)。
15. 使用样式美化CDF图
Matplotlib提供了多种样式选项,可以使图表更加美观:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
plt.style.use('seaborn')
data = np.random.normal(0, 1, 1000)
x, y = calculate_cdf(data)
plt.figure(figsize=(12, 7))
plt.plot(x, y, 'b-', linewidth=2, label='CDF')
plt.title('Styled CDF Plot', fontsize=16)
plt.xlabel('Value', fontsize=12)
plt.ylabel('Cumulative Probability', fontsize=12)
plt.legend(fontsize=10)
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
这个例子使用了’seaborn’样式,使图表看起来更加现代和专业。
16. 绘制多个CDF并添加图例
当需要在同一图表上比较多个分布时,清晰的图例非常重要:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
distributions = {
'Normal': np.random.normal(0, 1, 1000),
'Exponential': np.random.exponential(1, 1000),
'Uniform': np.random.uniform(-2, 2, 1000)
}
plt.figure(figsize=(12, 7))
for name, data in distributions.items():
x, y = calculate_cdf(data)
plt.plot(x, y, label=name)
plt.title('Comparison of Different Distributions', fontsize=16)
plt.xlabel('Value', fontsize=12)
plt.ylabel('Cumulative Probability', fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, linestyle='--', alpha=0.7)
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
这个示例绘制了三种不同分布的CDF,并添加了清晰的图例。
17. 使用颜色映射绘制CDF
使用颜色映射可以为CDF图添加额外的维度:
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
data = np.random.normal(0, 1, 1000)
x, y = calculate_cdf(data)
plt.figure(figsize=(12, 7))
plt.scatter(x, y, c=y, cmap='viridis', s=10)
plt.colorbar(label='Cumulative Probability')
plt.title('CDF with Color Mapping', fontsize=16)
plt.xlabel('Value', fontsize=12)
plt.ylabel('Cumulative Probability', fontsize=12)
plt.grid(True, linestyle='--', alpha=0.7)
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
这个例子使用颜色映射来表示累积概率,提供了一种视觉上更丰富的表示方法。
18. 绘制二维CDF
对于二维数据,我们可以绘制二维CDF:
from scipy import stats
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以确保结果可重现
np.random.seed(42)
x = np.random.normal(0, 1, 1000)
y = np.random.normal(0, 1, 1000)
xmin, xmax = x.min(), x.max()
ymin, ymax = y.min(), y.max()
xx, yy = np.mgrid[xmin:xmax:100j, ymin:ymax:100j]
positions = np.vstack([xx.ravel(), yy.ravel()])
values = np.vstack([x, y])
kernel = stats.gaussian_kde(values)
f = np.reshape(kernel(positions).T, xx.shape)
plt.figure(figsize=(12, 7))
plt.imshow(np.rot90(f), cmap='viridis', extent=[xmin, xmax, ymin, ymax])
plt.colorbar(label='Density')
plt.title('2D Cumulative Distribution Function', fontsize=16)
plt.xlabel('X', fontsize=12)
plt.ylabel('Y', fontsize=12)
plt.text(0.5, 0.5, 'how2matplotlib.com', ha='center', va='center', transform=plt.gca().transAxes, alpha=0.2, fontsize=40)
plt.show()
Output:
这个示例创建了一个二维CDF的热图表示。
总结
本文详细介绍了如何使用Python的Matplotlib库计算和绘制累积分布函数。我们从基本概念开始,逐步深入到更复杂的应用,包括美化图表、比较多个分布、添加置信区间、使用对数刻度等。通过这些示例,读者应该能够掌握使用Matplotlib绘制CDF的各种技巧,并能够根据具体需求定制自己的CDF图表。
CDF是数据分析和可视化中的重要工具,它可以帮助我们更好地理解数据的分布特征。通过本文提供的示例,读者可以将这些技术应用到自己的数据分析项目中,创建信息丰富、视觉吸引力强的CDF图表。
记住,在实际应用中,选择合适的可视化方法取决于数据的性质和你想要传达的信息。CDF图表是一种强大的工具,但它并不是唯一的选择。根据具体情况,你可能还需要考虑其他类型的图表,如直方图、箱线图或核密度估计图等。
最后,持续练习和实验是提高数据可视化技能的关键。尝试将本文中的技术应用到你自己的数据集上,并探索Matplotlib提供的其他功能,以创建更加丰富和有洞察力的可视化效果。