译文出品:Python数据之道
原文作者:Rizky Maulana Nurhidayat
翻译:Lemon
Matplotlib 实操干货
本文是 Matplotlib 可视化的第二篇。在第一篇文章中,我们学习了如何生成和自定义散点图、折线图、直方图和条形图。本文将继续使用 Matplotlib 在 Python 绘图中进行研究,涉及生成和自定义箱形图、小提琴图、饼图、极坐标图、地理投影、3D图和等高线图。
「Python数据之道」注,文末提供包括第一篇和第二篇的完整pdf文件获取方式。
与第一篇文章中一样,我已经在 Matplotlib 中自定义了默认参数。这是我的绘画风格:
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['text.usetex'] = True
plt.rcParams['font.size'] = 15
plt.rcParams['font.family'] = "serif"
tdir = 'in'
major = 5.0
minor = 3.0
plt.rcParams['xtick.direction'] = tdir
plt.rcParams['ytick.direction'] = tdir
plt.rcParams['xtick.major.size'] = major
plt.rcParams['xtick.minor.size'] = minor
plt.rcParams['ytick.major.size'] = major
plt.rcParams['ytick.minor.size'] = minor
01. 箱形图(Box plot)
你知道箱形图吗?维基百科将箱形图定义为一种通过四分位数以图形方式描绘数字数据组的方法。它用于描述性统计。您可以在 图1 中看到箱形图的示例。
通常,箱形图表示分布图。它是由一个框体、晶须和离群值构成的。在 图1 中,没有异常值。在框体元素中,可以显示分布的中位数或均值。我们可以在 图1 中看到中位数。该框体受 Q1(第一个四分位数)和 Q3(第三个四分位数)值的限制。Q1 和 Q3 的差值称为四分位数(IQR)。默认情况下,晶须显示分布的边界,最小值和最大值。
在 图2 中,可以看到一个异常值。箱形图如何检测离群值?
当其值小于 Q1-1.5 x IQR 或大于 Q3 + 1.5 x IQR 时,将在箱形图中检测到异常值。
在使用 Matplotlib 创建箱形图之前,将使用下面的代码生成模拟数据:
N = 50
np.random.seed(100)
box1 = np.random.randn(N) * 2 + 1
要以箱形图的形式显示变量 box1 ,可以使用以下代码:
plt.figure()
plt.boxplot(box1)
运行上面的代码时,可以在 图3 中看到结果:
水平箱形图 (Horizontal box plot)
如果要水平更改箱形图的方向,则需要在 plt.boxplot()
代码中应用以下参数。
vert = False
水平箱形图如 图4 所示:
在下一个示例中,将通过更改随机数据来创建一个具有异常值的分布,如以下代码所示:
N = 50
np.random.seed(140)
box1 = np.random.randn(N) * 2 + 1
plt.boxplot(box1, vert=False)
运行代码后,如 图5 所示:
下面将展示 Matplotlib 如何通过计算 Q1–1.5 x IQR,Q3 + 1.5 x IQR 的值并使用以下代码对分布进行排序来检测离群值:
q1 = np.quantile(box1, .25)
q3 = np.quantile(box1, .75)
iqr = q3-q1
lower_boundary = q1 - 1.5 * iqr
upper_boundary = q3 + 1.5 * iqr
sort = np.sort(box1)
为了可视化需要的值,可以运行以下代码:
N = 50
np.random.seed(140)
box1 = np.random.randn(N) * 2 + 1
q1 = np.quantile(box1, .25)
q3 = np.quantile(box1, .75)
iqr = q3-q1
lower_boundary = q1 - 1.5 * iqr
upper_boundary = q3 + 1.5 * iqr
sort = np.sort(box1)
colors = ['#6b2983', '#5f82cb', '#00d6ff', '#e77ca3', '#93003a']
plt.figure(figsize=(9, 3.5))
plt.boxplot(box1, vert=False)
plt.scatter(box1, np.linspace(1.3, 1.3, box1.shape[0]), color = 'r', alpha = .4, label = 'random numbers')
plt.vlines(lower_boundary, ymin = 0.2, ymax=.65, alpha = .7, ls = '-.', color = 'k', label = 'Q1 - 1.5 x IQR')
plt.vlines(sort[0], ymin = 0.2, ymax = .65, ls = '-', lw = 1.25, color = colors[2], label = 'minimum')
plt.vlines(sort[-2], ymin = 0.2, ymax = .65, ls = '-', lw = 1.25, color = colors[3], label = 'maximum')
plt.vlines(sort[-1], ymin = 0.2, ymax = .65, ls = '-', lw = 1.25, color = colors[4], label = 'outliers')
plt.vlines(upper_boundary, ymin = 0.2, ymax=.65, alpha = .7, ls = '--', color = 'k', label = 'Q3 + 1.5 x IQR')
plt.annotate(np.round(lower_boundary, 2), xy = (lower_boundary, 0.7), ha = 'center', color = 'k')
plt.annotate(np.round(sort[0], 2), xy = (sort[0], 0.7), ha = 'center', color = colors[2])
plt.annotate(np.round(sort[-2], 2), xy = (sort[-2], 0.7), ha = 'center', color = colors[3])
plt.annotate(np.round(sort[-1], 2), xy = (sort[-1], 0.7), ha = 'center', color = colors[4])
plt.annotate(np.round(upper_boundary, 2), xy = (upper_boundary, 0.8), ha = 'center', color = 'k')
plt.legend(bbox_to_anchor = (1.0, 1.05))
plt.savefig('box4.png', dpi = 300, bbox_inches = 'tight', facecolor='w')
上述代码运行的结果如 图6 所示:
在 图6 中,可以看到在红点中生成的随机数。下边界(Q1-1.5 x IQR)等于 -3.69,分布的最小值是 -2.41 。因此,图6 中的左晶须极限为最小值 -2.41。上限(Q3 + 1.5 x IQR)在 5.98 上,因此值 7.0 的数据被定义为离群值。晶须右边的极限值将在 5.47 处结束,处在上限之前的最大值。
在下一个示例中,将显示四个分布的平均值。需要使用以下代码为四个分布创建模拟数据:
np.random.seed(1214)
data = [np.random.normal(0, std, 100) for std in range(10, 14)]
显示均值
数据将生成四个正态分布,其中 mu 的值为0,并且每个分布的 sigma 值不同(10、11、12和13)。要在箱形图中显示均值,需要使用以下代码:
plt.boxplot(data, showmeans=True)
如果运行上面的代码,将生成一个箱形图,如 图7-1 所示。绿色三角形代表每个箱形图的均值:
同样的,可以使用下面代码在水平方箱形图中显示均值:
plt.boxplot(data, showmeans=True, vert = False)
运行代码,如 图7-2 所示:
可以通过添加以下参数来更改均值显示的符号:
meanline=True
或使用以下参数隐藏框体形状:
showbox=False
箱形图中的一些自定义设置如 图8 所示:
要更改框体的颜色可以使用以下设置进行操作。首先,需要设置下面的参数,代码所示如下:
patch_artist=True
然后,准备颜色,并使用以下代码将其应用到箱形图中:
colors = ['royalblue', 'lightblue', 'lightgreen', 'pink']
for patch, color in zip(box['boxes'], colors):
patch.set_facecolor(color)
以下是完整的代码:
np.random.seed(123)
all_data = [np.random.normal(0, std, 100) for std in range(10, 14)]
box = plt.boxplot(all_data, notch=False, patch_artist=True)
colors = ['royalblue', 'lightblue', 'lightgreen', 'pink']
for patch, color in zip(box['boxes'], colors):
patch.set_facecolor(color)
plt.ylim(-50, 50)
结果如 图9 所示:
激活缺口(Activate notch)
可以使用以下参数在箱形图中显示缺口,如 图10 所示:
notch=True
生成 图10 的完整代码如下:
np.random.seed(123)
all_data = [np.random.normal(0, std, 100) for std in range(10, 14)]
box = plt.boxplot(all_data, notch=True, patch_artist=True)
colors = ['royalblue', 'lightblue', 'lightgreen', 'pink']
for patch, color in zip(box['boxes'], colors):
patch.set_facecolor(color)
plt.ylim(-50, 50)
02. 小提琴图(Violin plot)
小提琴图与箱形图的可视化几乎相似,但未定义离群值。要创建小提琴图,可以使用以下代码:
N = 50
np.random.seed(140)
viol = np.random.randn(N) * 2 + 1
plt.figure()
plt.violinplot(viol)
以下代码将显示小提琴图,如 图11 所示:
水平的小提琴图,设置如下: