Matplotlib中使用plt.hist绘制直方图并设置y轴最大值为1
Matplotlib是Python中最流行的数据可视化库之一,它提供了丰富的绘图功能,其中直方图(Histogram)是一种常用的数据分布展示方式。在本文中,我们将深入探讨如何使用Matplotlib的plt.hist
函数绘制直方图,并重点关注如何将y轴的最大值设置为1,这种技术通常用于绘制概率密度直方图或归一化的频率直方图。
1. 直方图的基本概念
直方图是一种用于显示数据分布的图形,它将连续的数据分成若干个区间(称为”箱”或”bin”),然后计算每个区间内数据点的数量或频率。直方图的x轴表示数据的区间,y轴表示每个区间内的频数或频率。
在Matplotlib中,我们使用plt.hist
函数来创建直方图。这个函数非常灵活,可以根据需要调整多种参数来定制直方图的外观和行为。
让我们从一个简单的例子开始:
import matplotlib.pyplot as plt
import numpy as np
# 生成随机数据
data = np.random.randn(1000)
# 绘制直方图
plt.hist(data, bins=30, edgecolor='black')
plt.title('Simple Histogram - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()
Output:
在这个例子中,我们生成了1000个服从标准正态分布的随机数,然后使用plt.hist
函数绘制了一个包含30个箱的直方图。edgecolor='black'
参数设置了每个柱子的边框颜色为黑色,使得图形更加清晰。
2. 设置y轴最大值为1
在某些情况下,我们可能希望将直方图的y轴最大值设置为1。这通常用于以下两种情况:
- 绘制概率密度直方图
- 绘制归一化的频率直方图
要实现这一点,我们需要使用plt.hist
函数的density
参数和plt.ylim
函数。
2.1 使用density参数
density
参数是plt.hist
函数的一个重要选项。当设置density=True
时,直方图将被归一化,使得所有柱子下的总面积等于1。这样得到的直方图实际上是一个概率密度估计。
让我们看一个例子:
import matplotlib.pyplot as plt
import numpy as np
# 生成随机数据
data = np.random.randn(1000)
# 绘制归一化的直方图
plt.hist(data, bins=30, density=True, edgecolor='black')
plt.title('Normalized Histogram - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Density')
plt.ylim(0, 1) # 设置y轴范围为0到1
plt.show()
Output:
在这个例子中,我们添加了density=True
参数,使直方图被归一化。然后,我们使用plt.ylim(0, 1)
将y轴的范围设置为0到1。这样,我们就得到了一个y轴最大值为1的直方图。
2.2 手动归一化
有时候,我们可能想要更精确地控制归一化过程。在这种情况下,我们可以手动计算频率,然后使用这些频率值来绘制直方图。
下面是一个手动归一化的例子:
import matplotlib.pyplot as plt
import numpy as np
# 生成随机数据
data = np.random.randn(1000)
# 计算直方图数据
counts, bins, _ = plt.hist(data, bins=30)
# 计算频率
frequencies = counts / len(data)
# 清除之前的图形
plt.clf()
# 使用频率绘制直方图
plt.bar(bins[:-1], frequencies, width=np.diff(bins), edgecolor='black', align='edge')
plt.title('Manually Normalized Histogram - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.ylim(0, 1) # 设置y轴范围为0到1
plt.show()
Output:
在这个例子中,我们首先使用plt.hist
计算直方图数据,但不绘制图形。然后,我们手动计算每个箱的频率。最后,我们使用plt.bar
函数绘制频率直方图,并将y轴范围设置为0到1。
3. 自定义直方图外观
除了设置y轴最大值为1,我们还可以通过多种方式自定义直方图的外观,使其更加美观和信息丰富。
3.1 设置颜色和透明度
我们可以使用color
和alpha
参数来设置直方图的颜色和透明度:
import matplotlib.pyplot as plt
import numpy as np
data = np.random.randn(1000)
plt.hist(data, bins=30, density=True, color='skyblue', alpha=0.7, edgecolor='black')
plt.title('Customized Color Histogram - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Density')
plt.ylim(0, 1)
plt.show()
Output:
在这个例子中,我们将直方图的颜色设置为天蓝色('skyblue'
),并将透明度设置为0.7。这样可以使图形看起来更加柔和。
3.2 添加网格线
添加网格线可以帮助读者更准确地读取图表中的值:
import matplotlib.pyplot as plt
import numpy as np
data = np.random.randn(1000)
plt.hist(data, bins=30, density=True, color='lightgreen', edgecolor='black')
plt.title('Histogram with Grid - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Density')
plt.ylim(0, 1)
plt.grid(True, linestyle='--', alpha=0.7)
plt.show()
Output:
这里我们使用plt.grid
函数添加了网格线,并设置了线型和透明度。
3.3 添加平均值和标准差线
在直方图上添加平均值和标准差线可以提供更多的统计信息:
import matplotlib.pyplot as plt
import numpy as np
data = np.random.randn(1000)
plt.hist(data, bins=30, density=True, color='lightcoral', edgecolor='black')
plt.axvline(data.mean(), color='red', linestyle='dashed', linewidth=2, label='Mean')
plt.axvline(data.mean() + data.std(), color='green', linestyle='dashed', linewidth=2, label='+1 Std Dev')
plt.axvline(data.mean() - data.std(), color='green', linestyle='dashed', linewidth=2, label='-1 Std Dev')
plt.title('Histogram with Statistics - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Density')
plt.ylim(0, 1)
plt.legend()
plt.show()
Output:
在这个例子中,我们使用plt.axvline
函数添加了表示平均值和标准差的垂直线。
4. 多数据集比较
有时我们需要在同一个图表中比较多个数据集的分布。Matplotlib允许我们轻松地在一个图表中绘制多个直方图。
4.1 重叠直方图
我们可以通过调整透明度来创建重叠的直方图:
import matplotlib.pyplot as plt
import numpy as np
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(2, 1, 1000)
plt.hist(data1, bins=30, alpha=0.5, density=True, label='Dataset 1')
plt.hist(data2, bins=30, alpha=0.5, density=True, label='Dataset 2')
plt.title('Overlapping Histograms - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Density')
plt.ylim(0, 1)
plt.legend()
plt.show()
Output:
这个例子创建了两个不同的数据集,并用不同的颜色绘制它们的直方图。通过设置alpha=0.5
,我们可以看到两个分布的重叠部分。
4.2 并排直方图
对于并排比较,我们可以使用plt.subplots
创建多个子图:
import matplotlib.pyplot as plt
import numpy as np
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(2, 1, 1000)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
ax1.hist(data1, bins=30, density=True, color='skyblue', edgecolor='black')
ax1.set_title('Dataset 1 - how2matplotlib.com')
ax1.set_ylim(0, 1)
ax2.hist(data2, bins=30, density=True, color='lightgreen', edgecolor='black')
ax2.set_title('Dataset 2 - how2matplotlib.com')
ax2.set_ylim(0, 1)
plt.tight_layout()
plt.show()
Output:
这个例子创建了两个并排的子图,每个子图显示一个数据集的直方图。
5. 累积直方图
累积直方图是另一种有用的数据可视化工具,它显示了数据中小于或等于某个值的观测值的累积数量或比例。
import matplotlib.pyplot as plt
import numpy as np
data = np.random.randn(1000)
plt.hist(data, bins=30, density=True, cumulative=True, color='lightblue', edgecolor='black')
plt.title('Cumulative Histogram - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Cumulative Density')
plt.ylim(0, 1)
plt.grid(True, linestyle='--', alpha=0.7)
plt.show()
Output:
在这个例子中,我们添加了cumulative=True
参数来创建累积直方图。注意,累积直方图的y轴最大值自然就是1,因为它表示的是累积概率。
6. 2D直方图
对于二维数据,我们可以创建2D直方图,也称为热图(heatmap)。这种图表可以显示两个变量之间的联合分布。
import matplotlib.pyplot as plt
import numpy as np
x = np.random.randn(1000)
y = np.random.randn(1000)
plt.hist2d(x, y, bins=30, density=True, cmap='viridis')
plt.colorbar(label='Density')
plt.title('2D Histogram - how2matplotlib.com')
plt.xlabel('X Value')
plt.ylabel('Y Value')
plt.show()
Output:
这个例子使用plt.hist2d
函数创建了一个2D直方图。density=True
参数确保了颜色表示的是密度而不是计数。
7. 直方图与核密度估计的比较
核密度估计(KDE)是另一种估计概率密度函数的方法,它通常被认为比直方图更平滑。我们可以在同一图表中比较直方图和KDE:
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
data = np.random.randn(1000)
plt.hist(data, bins=30, density=True, alpha=0.7, color='lightblue', edgecolor='black')
kde = stats.gaussian_kde(data)
x_range = np.linspace(data.min(), data.max(), 100)
plt.plot(x_range, kde(x_range), 'r-', label='KDE')
plt.title('Histogram vs KDE - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Density')
plt.ylim(0, 1)
plt.legend()
plt.show()
Output:
这个例子首先绘制了一个直方图,然后使用SciPy的gaussian_kde
函数计算并绘制了KDE曲线。
8. 处理大数据集
当处理大数据集时,直方图可能会变得非常密集,难以解释。在这种情况下,我们可以使用对数刻度或增加箱的数量:
import matplotlib.pyplot as plt
import numpy as np
data = np.random.exponential(1, 1000000)
plt.hist(data, bins=100, density=True, color='lightgreen', edgecolor='black')
plt.title('Histogram of Large Dataset - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Density')
plt.yscale('log') # 使用对数刻度
plt.ylim(1e-6, 1) # 设置y轴范围
plt.show()
Output:
这个例子生成了一个包含100万个数据点的大数据集,并使用100个箱来创建直方图。我们还使用了对数刻度来更好地显示分布的尾部。
9. 自定义箱的边界
有时,我们可能想要自定义箱的边界,而不是使用自动生成的边界:
import matplotlib.pyplot as plt
import numpy as np
data = np.random.randn(1000)
custom_bins = [-3, -2, -1, 0, 1, 2, 3]
plt.hist(data, bins=custom_bins, density=True, color='lightcoral', edgecolor='black')
plt.title('Histogram with Custom Bins - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Density')
plt.ylim(0, 1)
plt.show()
Output:
在这个例子中,我们定义了一个自定义的箱边界列表custom_bins
,并将其传递给plt.hist
函数的bins
参数。这允许我们精确控制直方图的箱划分。
10. 堆叠直方图
堆叠直方图是比较多个类别或组的分布的有效方式:
import matplotlib.pyplot as plt
import numpy as np
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(1, 1, 1000)
data3 = np.random.normal(2, 1, 1000)
plt.hist([data1, data2, data3], bins=30, density=True, stacked=True, label=['Group 1', 'Group 2', 'Group 3'])
plt.title('Stacked Histogram - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Density')
plt.ylim(0, 1)
plt.legend()
plt.show()
Output:
在这个例子中,我们创建了三个不同的数据集,并使用stacked=True
参数来创建堆叠直方图。每个组都用不同的颜色表示,使得比较变得容易。
11. 直方图与散点图的结合
有时,将直方图与散点图结合可以提供更全面的数据视图:
import matplotlib.pyplot as plt
import numpy as np
x = np.random.randn(1000)
y = np.random.randn(1000)
fig, axs = plt.subplots(2, 2, figsize=(10, 10))
# 散点图
axs[0, 0].scatter(x, y, alpha=0.5)
axs[0, 0].set_title('Scatter Plot - how2matplotlib.com')
# x的直方图
axs[0, 1].hist(x, bins=30, density=True)
axs[0, 1].set_title('Histogram of X - how2matplotlib.com')
axs[0, 1].set_ylim(0, 1)
# y的直方图
axs[1, 0].hist(y, bins=30, density=True, orientation='horizontal')
axs[1, 0].set_title('Histogram of Y - how2matplotlib.com')
axs[1, 0].set_xlim(0, 1)
# 空白子图
axs[1, 1].axis('off')
plt.tight_layout()
plt.show()
Output:
这个例子创建了一个2×2的子图网格,包含一个散点图和两个直方图(一个用于x值,一个用于y值)。这种组合可以同时显示两个变量的联合分布和各自的边缘分布。
12. 使用Seaborn绘制美观的直方图
虽然Matplotlib非常强大,但有时我们可能想要更美观的默认样式。Seaborn是基于Matplotlib的统计数据可视化库,它提供了更现代和吸引人的默认样式:
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
sns.set_style("whitegrid")
data = np.random.randn(1000)
sns.histplot(data, kde=True, stat="density")
plt.title('Seaborn Histogram - how2matplotlib.com')
plt.xlabel('Value')
plt.ylabel('Density')
plt.ylim(0, 1)
plt.show()
Output:
这个例子使用Seaborn的histplot
函数创建了一个直方图,并自动添加了核密度估计曲线。Seaborn的默认样式通常被认为比Matplotlib的更加美观。
13. 动态调整箱的数量
选择适当数量的箱对于创建信息丰富的直方图至关重要。我们可以使用Matplotlib的交互式功能来动态调整箱的数量:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.widgets import Slider
data = np.random.randn(1000)
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)
hist, bins, _ = ax.hist(data, bins=30, density=True)
ax.set_ylim(0, 1)
ax_slider = plt.axes([0.2, 0.1, 0.6, 0.03])
slider = Slider(ax_slider, 'Bins', 5, 100, valinit=30, valstep=1)
def update(val):
ax.clear()
ax.hist(data, bins=int(slider.val), density=True)
ax.set_ylim(0, 1)
ax.set_title('Interactive Histogram - how2matplotlib.com')
fig.canvas.draw_idle()
slider.on_changed(update)
plt.show()
Output:
这个例子创建了一个带有滑块的交互式直方图。用户可以通过移动滑块来实时调整箱的数量,从而探索数据的不同表示。
14. 3D直方图
对于某些应用,3D直方图可能是有用的。虽然它们可能不如2D直方图易于解释,但它们可以提供数据的独特视角:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.random.normal(0, 1, 1000)
y = np.random.normal(0, 1, 1000)
hist, xedges, yedges = np.histogram2d(x, y, bins=20, density=True)
xpos, ypos = np.meshgrid(xedges[:-1] + 0.25, yedges[:-1] + 0.25, indexing="ij")
xpos = xpos.ravel()
ypos = ypos.ravel()
zpos = 0
dx = dy = 0.5 * np.ones_like(zpos)
dz = hist.ravel()
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, zsort='average')
ax.set_title('3D Histogram - how2matplotlib.com')
ax.set_xlabel('X Value')
ax.set_ylabel('Y Value')
ax.set_zlabel('Density')
ax.set_zlim(0, 1)
plt.show()
Output:
这个例子创建了一个3D直方图,其中x和y轴表示数据的两个维度,z轴表示每个箱中的密度。
15. 直方图与箱线图的结合
直方图和箱线图都是展示数据分布的有效工具。将它们结合在一起可以提供更全面的数据视图:
import matplotlib.pyplot as plt
import numpy as np
data = np.random.randn(1000)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 10), sharex=True)
ax1.hist(data, bins=30, density=True)
ax1.set_title('Histogram - how2matplotlib.com')
ax1.set_ylabel('Density')
ax1.set_ylim(0, 1)
ax2.boxplot(data, vert=False)
ax2.set_title('Box Plot - how2matplotlib.com')
ax2.set_xlabel('Value')
plt.tight_layout()
plt.show()
Output:
这个例子在上半部分绘制了一个直方图,在下半部分绘制了一个箱线图。这种组合可以同时显示数据的整体分布和关键统计信息(如中位数、四分位数和异常值)。
总结起来,Matplotlib提供了丰富的工具来创建和自定义直方图,特别是在设置y轴最大值为1的情况下。通过调整各种参数和结合不同的图表类型,我们可以创建出既美观又信息丰富的数据可视化。无论是用于数据分析、科学研究还是数据报告,掌握这些技巧都将大大提升我们的数据可视化能力。