Python中可视化数据(直方图和密度图)

albertjone 2018-03-24

本文将全面介绍如何使用matplotlib和seaborn库在Python中使用直方图和密度图。在整个过程中,我们将探索一个真实世界的数据集,因为在网上提供大量资源的情况下,没有理由不使用实际数据!我们将可视化的NYCflights13数据,其中包含超过300,000个航班离开纽约市的航班2013年的观测数据。

在我们开始绘图之前先检查我们的数据。我们可以将数据读入熊猫数据框并显示前10行:

import pandas as pd
# Read in data and examine first 10 rows
flights = pd.read_csv('data/formatted_flights.csv')
flights.head(10)

Python中可视化数据(直方图和密度图)

Dataframe负责人

航班到达延误在几分钟内,负值意味着航班较早(事实证明,航班往往会提早到达,只是从来没有当我们在他们身上!)有超过30万次的航班,至少延迟60分钟和最大延迟时间为120分钟。数据框中的另一列是我们可用于比较的航空公司的名称。

直方图

为了使 Python 中的基本直方图, 我们可以使用 matplotlib 或 seaborn。下面的代码显示两个库中创建等效数字的函数调用。对于绘图调用, 我们指定 binwidth 的数量。

# Import the libraries

import matplotlib.pyplot as plt

import seaborn as sns

# matplotlib histogram

plt.hist(flights['arr_delay'], color = 'blue', edgecolor = 'black',

bins = int(180/5))

# seaborn histogram

sns.distplot(flights['arr_delay'], hist=True, kde=False,

bins=int(180/5), color = 'blue',

hist_kws={'edgecolor':'black'})

# Add labels

plt.title('Histogram of Arrival Delays')

plt.xlabel('Delay (min)')

plt.ylabel('Flights')

Python中可视化数据(直方图和密度图)

直方图(由matplotlib和seaborn生成的等效图)

对于大多数基本的直方图,我会使用matplotlib代码,因为它更简单,但我们稍后将使用seaborn distplot函数来创建不同的分布。

我怎么得到5分钟的binwidth?找出最佳binwidth的唯一方法是尝试多个值!下面的代码是在matplotlib中使用一系列binwidth来制作相同的图形。最终,对于binwidth没有正确或错误的答案,但我选择5分钟,因为我认为它最能代表分布。

# Show 4 different binwidths

for i, binwidth in enumerate([1, 5, 10, 15]):

# Set up the plot

ax = plt.subplot(2, 2, i + 1)

# Draw the plot

ax.hist(flights['arr_delay'], bins = int(180/binwidth),

color = 'blue', edgecolor = 'black')

# Title and labels

ax.set_title('Histogram with Binwidth = %d' % binwidth, size = 30)

ax.set_xlabel('Delay (min)', size = 22)

ax.set_ylabel('Flights', size= 22)

plt.tight_layout()

plt.show()

Python中可视化数据(直方图和密度图)

不同带宽的直方图

binwidth的选择会显着影响结果图。较小的带宽可能会使绘图混乱,但较大的带宽可能会掩盖数据中的细微差别。Matplotlib会自动为你选择一个合理的binwidth,但我喜欢在尝试了几个值后自己指定binwidth。没有真正的正确或错误答案,因此请尝试几个选项并查看哪些最适合您的特定数据。

当直方图失败时

直方图是开始探索从一个类别中提取的单个变量的一个很好的方法。但是, 当我们要比较一个变量分布在多个类别, 直方图有问题的可读性。例如, 如果我们要比较航空公司之间的到达延迟分布, 一个不太好的方法是在同一地块上为每家航空公司创建直方图:

Python中可视化数据(直方图和密度图)

与多个航空公司重叠的直方图

(请注意,y轴已被标准化以考虑航空公司之间航班的不同数量。为此,请将参数传递norm_hist = True给sns.distplot函数调用。)

解决方案#1:并排直方图

我们可以将它们并排放置,而不是重叠航空公司的直方图。为此,我们为每家航空公司创建一个到达延迟列表,然后将其plt.hist作为列表列表传递给函数调用。我们必须为每家航空公司和一个标签指定不同的颜色,以便我们可以区分它们。代码,包括为每家航空公司创建列表如下:

# Make a separate list for each airline

x1 = list(flights[flights['name'] == 'United Air Lines Inc.']['arr_delay'])

x2 = list(flights[flights['name'] == 'JetBlue Airways']['arr_delay'])

x3 = list(flights[flights['name'] == 'ExpressJet Airlines Inc.']['arr_delay'])

x4 = list(flights[flights['name'] == 'Delta Air Lines Inc.']['arr_delay'])

x5 = list(flights[flights['name'] == 'American Airlines Inc.']['arr_delay'])

# Assign colors for each airline and the names

colors = ['#E69F00', '#56B4E9', '#F0E442', '#009E73', '#D55E00']

names = ['United Air Lines Inc.', 'JetBlue Airways', 'ExpressJet Airlines Inc.'',

'Delta Air Lines Inc.', 'American Airlines Inc.']

# Make the histogram using a list of lists

# Normalize the flights and assign colors and names

plt.hist([x1, x2, x3, x4, x5], bins = int(180/15), normed=True,

color = colors, label=names)

# Plot formatting

plt.legend()

plt.xlabel('Delay (min)')

plt.ylabel('Normalized Flights')

plt.title('Side-by-Side Histogram with Multiple Airlines')

Python中可视化数据(直方图和密度图)

默认情况下,如果我们传入列表列表,matplotlib将并排放置条形图。

解决方案 #2: 堆积条形图

我们可以通过将参数传递stacked = True给直方图调用来堆叠它们,而不是为每个航空公司并排绘制条形图:

# Stacked histogram with multiple airlines
plt.hist([x1, x2, x3, x4, x5], bins = int(180/15), stacked=True,
normed=True, color = colors, label=names)

Python中可视化数据(直方图和密度图)

那么,这绝对不是更好!在这里,每个航空公司都代表每个舱位的整体部分,但几乎不可能进行比较。我们使用直方图尝试的两种解决方案都不成功,因此是时候转移到密度图。

密度图

首先,什么是密度图?甲密度图是从数据中估计的直方图的平滑化,连续版本。最常见的估计形式被称为核密度估计。在这种方法中,在每个单独的数据点处绘制连续曲线(内核),然后将所有这些曲线相加在一起以进行单个平滑密度估计。最常用的内核是高斯(在每个数据点产生高斯钟形曲线)。

Python中可视化数据(直方图和密度图)

Kernel Density Estimation

这里,x轴上的每条黑色小垂直线代表一个数据点。单个内核(本例中为高斯)在每个点上方用红色虚线表示。坚实的蓝色曲线是通过对各个高斯求和来创建的,并形成整体密度图。

x轴是变量的值,就像直方图一样,但y轴代表什么?密度图中的y轴是核密度估计的概率密度函数。但是,我们需要小心地指定这是一个概率密度,而不是概率。不同之处在于概率密度是x轴上每单位的概率。要转换为实际概率,我们需要在x轴上找到特定间隔下曲线下方的区域。有点令人困惑的是,因为这是一个概率密度而不是概率,所以y轴可以取大于1的值。密度图的唯一要求是曲线下的总面积合并为一。我通常倾向于将密度图上的y轴视为仅用于不同类别之间的相对比较的值。

Seaborn中的密度图

为了使 seaborn 中的密度图, 我们可以使用 distplot 或 kdeplot 函数。我将继续使用 distplot 函数, 因为它允许我们用一个函数调用进行多个分布。例如, 我们可以使一个密度图显示所有到达延迟在对应的直方图之上:

# Density Plot and Histogram of all arrival delays
sns.distplot(flights['arr_delay'], hist=True, kde=True,
bins=int(180/5), color = 'darkblue',
hist_kws={'edgecolor':'black'},
kde_kws={'linewidth': 4})

Python中可视化数据(直方图和密度图)

曲线显示了密度图, 它实质上是直方图的平滑版本。y 轴是按密度计算的, 而直方图在缺省情况下是规范化的, 因此它与密度图具有相同的 y 尺度。

与直方图的 binwidth 类似, 密度图有一个参数称为带宽,绘图库将为我们选择一个合理的带宽值 (默认情况下使用 "斯科特" 估计), 而不像直方图的 binwidth, 我通常使用默认带宽。但是, 我们可以使用不同的带宽来查看是否有更好的选择。

Python中可视化数据(直方图和密度图)

请注意,更宽的带宽会使分配更平滑。我们也看到,即使我们将数据限制在-60到120分钟,密度图也超出了这些限制。这是密度图的一个潜在问题:因为它计算每个数据点的分布,所以它可以生成超出原始数据范围的数据。这可能意味着我们最终会得到原始数据中从来不存在的x轴上不可能的值!值得注意的是,我们也可以更改内核,这会改变在每个数据点处绘制的分布,从而改变整体分布。但是,对于大多数应用程序,默认的内核,高斯和默认的带宽估计工作得很好。

解决方案#3密度图

为了在同一个图上显示分布,我们可以遍历航空公司,每次调用distplot内核密度估计值设置为True并将直方图设置为False。下面是用多个航空公司绘制密度图的代码:

# List of five airlines to plot

airlines = ['United Air Lines Inc.', 'JetBlue Airways', 'ExpressJet Airlines Inc.'',

'Delta Air Lines Inc.', 'American Airlines Inc.']

# Iterate through the five airlines

for airline in airlines:

# Subset to the airline

subset = flights[flights['name'] == airline]

# Draw the density plot

sns.distplot(subset['arr_delay'], hist = False, kde = True,

kde_kws = {'linewidth': 3},

label = airline)

# Plot formatting

plt.legend(prop={'size': 16}, title = 'Airline')

plt.title('Density Plot with Multiple Airlines')

plt.xlabel('Delay (min)')

plt.ylabel('Density')

Python中可视化数据(直方图和密度图)

最后,我们已经达成了一个有效的解决方案!通过密度图,我们可以轻松地进行航空公司之间的比较,因为图形不那么混乱。我们得出这样的结论:所有这些航空公司都有几乎相同的到达延迟分布!但是,数据集中还有其他航空公司,我们可以绘制一个稍有不同的图形来说明密度图的另一个可选参数,并为图形着色。

阴影密度图

填充密度图可以帮助我们区分重叠分布。虽然这不总是一个好方法,但它可以帮助强调分布之间的差异。为了遮蔽密度图,我们传递shade = True给调用中的kde_kws参数distplot。

sns.distplot(subset ['arr_delay'],hist = False,kde = True,
 kde_kws = {'shade':True,'linewidth':3},
 label = airline)

Python中可视化数据(直方图和密度图)

阴影密度图

对于这个图表,我认为这是有道理的,因为阴影可以帮助我们区分它们重叠区域的地块。现在,我们终于获得了一些有用的信息:阿拉斯加航空公司的航班往往比联合航空公司的航班时间更早。

Rug Plots

如果要显示分布中的每个值而不仅是平滑密度,则可以添加小地图。这显示了x轴上的每个数据点,使我们可以看到所有的实际值。使用seaborn的好处distplot是,我们可以添加单个参数调用rug = True(具有一些格式化)的地毯情节。

# Subset to Alaska Airlines

subset = flights[flights['name'] == 'Alaska Airlines Inc.']

# Density Plot with Rug Plot

sns.distplot(subset['arr_delay'], hist = False, kde = True, rug = True,

color = 'darkblue',

kde_kws={'linewidth': 3},

rug_kws={'color': 'black'})

# Plot formatting

plt.title('Density Plot with Rug Plot for Alaska Airlines')

plt.xlabel('Delay (min)')

plt.ylabel('Density')

Python中可视化数据(直方图和密度图)

有了许多数据点, 地毯图会变得拥挤, 但是对于某些数据集来说, 查看每一个资料点都是有帮助的。

相关推荐