import plotly.express as px
import pandas as pd
import numpy as np
from vega_datasets import data
10 使用 Plotly Express 的双变量和多变量图
10.1 介绍
在本课程中,您将学习如何使用 Plotly Express 创建双变量和多变量图。这类图表对于探索两个或多个变量之间的关系至关重要,无论这些变量是定量的还是分类的。理解这些关系可以为您的数据提供更深入的见解。
让我们开始吧!
10.2 学习目标
在本课程结束时,您将能够:
- 为定量对定量数据创建散点图
- 为定量对分类数据生成分组直方图和小提琴图
- 为分类对分类数据创建分组、堆叠和百分比堆叠条形图
- 使用条形图和折线图可视化时间序列数据
- 创建气泡图以显示三个或更多变量之间的关系
- 使用分面图比较不同数据子集的分布
10.3 导入
本课程需要 plotly.express
、pandas
、numpy
和 vega_datasets
。如果尚未安装,请先安装它们。
10.4 数值与数值数据
当两个变量都是定量的时,散点图是可视化它们关系的绝佳方式。
10.4.1 散点图
让我们创建一个散点图来检查 total_bill
和 tip
在 tips 数据集中的关系。tips 数据集包含在 Plotly Express 中,其中包含美国餐厅服务员收集的餐账和小费信息。
首先,我们将加载数据集并查看前五行:
= px.data.tips()
tips tips
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
... | ... | ... | ... | ... | ... | ... | ... |
239 | 29.03 | 5.92 | Male | No | Sat | Dinner | 3 |
240 | 27.18 | 2.00 | Female | Yes | Sat | Dinner | 2 |
241 | 22.67 | 2.00 | Male | Yes | Sat | Dinner | 2 |
242 | 17.82 | 1.75 | Male | No | Sat | Dinner | 2 |
243 | 18.78 | 3.00 | Female | No | Thur | Dinner | 2 |
244 rows × 7 columns
接下来,我们将创建一个基本的散点图。我们将使用 px.scatter
函数来完成。
='total_bill', y='tip') px.scatter(tips, x
从散点图中,我们可以观察到,随着总账单的增加,小费金额也趋于增加。
让我们通过添加标签和标题来增强散点图。
px.scatter(
tips,="total_bill",
x="tip",
y={"total_bill": "总账单($)", "tip": "小费($)"},
labels="总账单与小费金额之间的关系",
title )
请记得,您可以在单元格中输入 px.scatter?
并执行单元格,以查看有关该函数的更多信息。
px.scatter?
10.4.2 练习题:预期寿命与人均 GDP
使用 Gapminder 数据集(以下定义的2007年子集 g_2007
),创建一个散点图,显示 gdpPercap
(人均 GDP)和 lifeExp
(预期寿命)之间的关系。
根据图表,人均 GDP 和预期寿命之间是什么关系?
= px.data.gapminder()
gapminder = gapminder.query('year == 2007')
g_2007
g_2007.head()# 您的代码在此处
country | continent | year | lifeExp | pop | gdpPercap | iso_alpha | iso_num | |
---|---|---|---|---|---|---|---|---|
11 | Afghanistan | Asia | 2007 | 43.828 | 31889923 | 974.580338 | AFG | 4 |
23 | Albania | Europe | 2007 | 76.423 | 3600523 | 5937.029526 | ALB | 8 |
35 | Algeria | Africa | 2007 | 72.301 | 33333216 | 6223.367465 | DZA | 12 |
47 | Angola | Africa | 2007 | 42.731 | 12420476 | 4797.231267 | AGO | 24 |
59 | Argentina | Americas | 2007 | 75.320 | 40301927 | 12779.379640 | ARG | 32 |
根据图表,人均 GDP 和预期寿命之间存在正相关关系,尽管在较高的 GDP 值时似乎趋于平稳。
10.5 数值与分类数据
当一个变量是定量的,另一个是分类的时,我们可以使用分组直方图、小提琴图或箱线图来可视化定量变量在不同类别中的分布。
10.5.1 分组直方图
首先,以下是如何创建所有小费的常规直方图:
='tip') px.histogram(tips, x
要创建分组直方图,请使用 color
参数指定分类变量。在这里,我们将按 sex
为直方图着色:
='tip', color='sex') px.histogram(tips, x
默认情况下,每个类别的直方图是堆叠的。要更改此行为,您可以使用 barmode
参数。例如,barmode='overlay'
将创建一个重叠的直方图:
="tip", color="sex", barmode="overlay") px.histogram(tips, x
这将在彼此之上创建两个半透明的直方图,从而允许直接比较分布。
10.5.2 练习题:按性别的年龄分布
使用 vega_datasets
中的 la_riots
数据集,创建按 gender
分组的 age
直方图。比较不同性别之间的年龄分布。
根据图表,年龄最大的受害者是男性还是女性?
= data.la_riots()
la_riots
la_riots.head()# 您的代码在此处
first_name | last_name | age | gender | race | death_date | address | neighborhood | type | longitude | latitude | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | Cesar A. | Aguilar | 18.0 | Male | Latino | 1992-04-30 | 2009 W. 6th St. | Westlake | Officer-involved shooting | -118.273976 | 34.059281 |
1 | George | Alvarez | 42.0 | Male | Latino | 1992-05-01 | Main & College streets | Chinatown | Not riot-related | -118.234098 | 34.062690 |
2 | Wilson | Alvarez | 40.0 | Male | Latino | 1992-05-23 | 3100 Rosecrans Ave. | Hawthorne | Homicide | -118.326816 | 33.901662 |
3 | Brian E. | Andrew | 30.0 | Male | Black | 1992-04-30 | Rosecrans & Chester avenues | Compton | Officer-involved shooting | -118.215390 | 33.903457 |
4 | Vivian | Austin | 87.0 | Female | Black | 1992-05-03 | 1600 W. 60th St. | Harvard Park | Death | -118.304741 | 33.985667 |
根据图表,年龄最大的受害者是女性。
10.5.3 小提琴图和箱线图
小提琴图对于比较定量变量在不同类别中的分布非常有用。它们显示了数据在不同值处的概率密度,并可以包括一个箱线图以总结关键统计量。
首先,让我们创建一个所有小费的小提琴图:
="tip") px.violin(tips, y
我们可以通过将 box
参数设置为 True
来在小提琴图中添加箱线图:
="tip", box=True) px.violin(tips, y
仅使用箱线图,我们可以使用 px.box
:
="tip") px.box(tips, y
要在小提琴图或箱线图中添加抖动点,我们可以使用 points='all'
参数。
="tip", points="all") px.violin(tips, y
现在,创建按性别分组的小提琴图,使用 x
参数指定分类变量:
="tip", x="sex", box=True) px.violin(tips, y
我们还可以添加颜色轴以区分小提琴图:
="tip", x="sex", color="sex", box=True) px.violin(tips, y
10.5.4 练习题:按洲分的预期寿命
使用 g_2007
数据集,创建一个显示 lifeExp
按 continent
分布的小提琴图。
根据图表,哪个洲的国家预期寿命中位数最高?
= gapminder.query("year == 2007")
g_2007
g_2007.head()# 您的代码在此处
country | continent | year | lifeExp | pop | gdpPercap | iso_alpha | iso_num | |
---|---|---|---|---|---|---|---|---|
11 | Afghanistan | Asia | 2007 | 43.828 | 31889923 | 974.580338 | AFG | 4 |
23 | Albania | Europe | 2007 | 76.423 | 3600523 | 5937.029526 | ALB | 8 |
35 | Algeria | Africa | 2007 | 72.301 | 33333216 | 6223.367465 | DZA | 12 |
47 | Angola | Africa | 2007 | 42.731 | 12420476 | 4797.231267 | AGO | 24 |
59 | Argentina | Americas | 2007 | 75.320 | 40301927 | 12779.379640 | ARG | 32 |
根据图表,澳大利亚大洋洲的国家预期寿命中位数最高。
10.5.5 摘要条形图(平均值和标准差)
有时,显示定量变量在不同类别中的平均值和标准差非常有用。这可以使用带有误差条的条形图来可视化。
首先,让我们计算每个性别的小费平均值和标准差。您尚未学习如何执行此操作,但在后续课程中会涉及。
# 计算平均值和标准差
= (
summary_df "sex")
tips.groupby(=("tip", "mean"), std_tip=("tip", "std"))
.agg(mean_tip
.reset_index()
) summary_df
sex | mean_tip | std_tip | |
---|---|---|---|
0 | Female | 2.833448 | 1.159495 |
1 | Male | 3.089618 | 1.489102 |
接下来,我们将使用 px.bar
创建条形图,并使用 error_y
参数添加误差条:
# 创建条形图
="sex", y="mean_tip", error_y="std_tip") px.bar(summary_df, x
此条形图显示了每个性别的平均小费金额,误差条表示标准差。
10.5.6 练习题:按天的平均总账单
使用 tips
数据集,创建一个带有标准差误差条的按 day
分组的平均 total_bill
条形图。您可以复制并粘贴上面的示例代码,并修改以创建此图。
根据图表,哪个星期天的平均总账单最高?
# 查看 tips 数据集
tips.head() # 您的代码在此处
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
根据图表,星期天的平均账单最高。
px.bar
和 px.histogram
之间的区别
请注意,这是我们第一次使用 px.bar
函数。在过去的图表中,我们使用 px.histogram
来制作条形图。
条形图函数通常期望被绘制的数值变量已经在自己的列中,而直方图函数会为您进行分组。
例如,在下面的单元格中,我们使用 px.histogram
制作 sex
列的条形图。生成的图表比较了数据集中男性和女性客户的数量。
='sex') px.histogram(tips, x
要使用 px.bar
制作相同的图表,我们首先需要按 sex
列分组并计算每个性别的行数。
= tips['sex'].value_counts().reset_index()
sex_counts sex_counts
sex | count | |
---|---|---|
0 | Male | 157 |
1 | Female | 87 |
然后,我们可以使用 px.bar
绘制 sex
列:
="sex", y="count") px.bar(sex_counts, x
这将生成一个每个性别一个条形的条形图。
10.6 分类与分类数据
当两个变量都是分类时,带有颜色轴的条形图对于可视化类别之间的频率分布非常有效。我们将重点介绍三种类型的条形图:堆叠条形图、百分比堆叠条形图和分组/集群条形图。
10.6.1 堆叠条形图
堆叠条形图显示总计和每个类别中的分解。要制作堆叠条形图,请使用 color
参数指定分类变量:
px.histogram(
tips,='day',
x='sex'
color )
让我们在条形上添加数字以显示确切的计数,并使用自定义颜色改善色彩调色板。
px.histogram(
tips,="day",
x="sex",
color=True,
text_auto=["#deb221", "#2f828a"],
color_discrete_sequence )
此堆叠条形图显示了每一天的总客户数量,按性别细分。
10.6.2 练习题:按洲的高收入和低收入国家
使用 g_2007_income
数据集,创建一个堆叠条形图,显示每个洲的高收入和低收入国家的数量。
= px.data.gapminder()
gap_dat
= (
g_2007_income "year == 2007")
gap_dat.query(=["year", "iso_alpha", "iso_num"])
.drop(columns
.assign(=lambda df: np.where(
income_group> 15000, "高收入", "低收入和中等收入"
df.gdpPercap
)
)
)
g_2007_income.head()# 您的代码在此处
country | continent | lifeExp | pop | gdpPercap | income_group | |
---|---|---|---|---|---|---|
11 | Afghanistan | Asia | 43.828 | 31889923 | 974.580338 | 低收入和中等收入 |
23 | Albania | Europe | 76.423 | 3600523 | 5937.029526 | 低收入和中等收入 |
35 | Algeria | Africa | 72.301 | 33333216 | 6223.367465 | 低收入和中等收入 |
47 | Angola | Africa | 42.731 | 12420476 | 4797.231267 | 低收入和中等收入 |
59 | Argentina | Americas | 75.320 | 40301927 | 12779.379640 | 低收入和中等收入 |
10.6.3 百分比堆叠条形图
要显示比例而不是计数,我们可以通过将 barnorm
参数设置为 'percent'
来创建百分比堆叠条形图:
# 创建百分比堆叠条形图
="day", color="sex", barnorm="percent") px.histogram(tips, x
此图表将条形高度规范化为表示百分比,显示每一天每个性别的比例。
我们还可以在条形上添加文本标签以显示确切的百分比:
="day", color="sex", barnorm="percent", text_auto=".1f") px.histogram(tips, x
text_auto
参数中的符号 .1f
将文本标签格式化为一位小数。
10.6.4 练习题:按洲的高收入和低收入国家比例
再次使用 g_2007_income
数据集,创建一个百分比堆叠条形图,显示每个洲高收入和低收入国家的比例。添加文本标签以显示确切的百分比。
根据图表,哪个洲的高收入国家比例最高?此图表有哪些限制?
# 您的代码在此处
10.6.5 集群条形图
对于集群条形图,将 barmode
参数设置为 'group'
以将每个类别的条形并排放置:
="day", color="sex", barmode="group") px.histogram(tips, x
这种布局使得跨类别的值比较更加容易。
10.7 时间序列数据
时间序列数据表示在不同时间点收集的观察值。它对于分析趋势、模式和随时间的变化至关重要。让我们使用 Gapminder 数据集中尼日利亚的人口数据探索一些基本的时间序列可视化。
首先,让我们准备数据:
# 加载 Gapminder 数据集
= px.data.gapminder()
gapminder
# 子集数据为尼日利亚
= gapminder.query('country == "Nigeria"')[['year', 'pop']]
nigeria_pop nigeria_pop
year | pop | |
---|---|---|
1128 | 1952 | 33119096 |
1129 | 1957 | 37173340 |
1130 | 1962 | 41871351 |
1131 | 1967 | 47287752 |
1132 | 1972 | 53740085 |
1133 | 1977 | 62209173 |
1134 | 1982 | 73039376 |
1135 | 1987 | 81551520 |
1136 | 1992 | 93364244 |
1137 | 1997 | 106207839 |
1138 | 2002 | 119901274 |
1139 | 2007 | 135031164 |
10.7.1 条形图
条形图可以用于绘制时间序列数据。
# 条形图
="year", y="pop") px.bar(nigeria_pop, x
此条形图清晰地展示了尼日利亚人口随年份的变化,每个条形代表特定年份的人口。
10.7.2 折线图
折线图非常适合显示随时间的连续变化:
# 折线图
="year", y="pop") px.line(nigeria_pop, x
折线图连接了人口值,使得整体人口增长趋势更易于观察。
在折线图中添加标记点可以突出显示特定的数据点:
# 带点的折线图
='year', y='pop', markers=True) px.line(nigeria_pop, x
我们还可以通过添加 color
参数来比较多个国家的人口增长:
= gapminder.query('country in ["Nigeria", "Ghana"]')
nigeria_ghana ="year", y="pop", color="country", markers=True) px.line(nigeria_ghana, x
此图表允许我们比较尼日利亚和加纳的人口增长趋势。
10.7.3 练习题:人均 GDP 时间序列
使用 Gapminder 数据集,创建伊拉克人均 GDP 的时间序列可视化。
# 您的代码在此处
1980 年代伊拉克发生了什么事件,可能解释了图表中的现象?
10.8 三个或更多变量的图表
虽然双变量可视化是最常见的可视化类型,但有时三个或更多变量的图表也是有用的。让我们探索一些示例。
10.8.1 气泡图
气泡图通过将点的大小映射到第三个变量来显示三个变量之间的关系。下面,我们绘制了 gdpPercap
和 lifeExp
之间的关系,点的大小表示国家的人口。
="gdpPercap", y="lifeExp", size="pop") px.scatter(g_2007, x
我们可以轻松地识别出人口最多的国家,如中国、印度和美国。我们还可以添加颜色轴以区分不同洲:
="gdpPercap", y="lifeExp", size="pop", color="continent") px.scatter(g_2007, x
现在我们绘制了四个不同的变量:
gdpPercap
在 x 轴lifeExp
在 y 轴pop
作为点的大小continent
作为点的颜色
10.8.2 练习题:小费气泡图
使用 tips
数据集,创建一个气泡图,显示 total_bill
和 tip
之间的关系,点的大小表示聚会的 size
,颜色表示星期几的 day
。
使用此图回答以下问题:
- 最高的两个小费金额是哪几天的,且桌子的人数是多少?
tips.head()# 您的代码在此处
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
10.8.3 分面图
分面图将单个图表拆分为多个图表,每个图表显示数据的不同子集。这对于比较不同子集之间的分布非常有用。
例如,我们可以按洲对气泡图进行分面:
px.scatter(
g_2007,="gdpPercap",
x="lifeExp",
y="pop",
size="continent",
color="continent",
facet_col )
我们可以通过更改 facet_col_wrap
参数来更改分面排列。例如,facet_col_wrap=2
将分面排列为两列:
px.scatter(
g_2007,="gdpPercap",
x="lifeExp",
y="pop",
size="continent",
color="continent",
facet_col=2,
facet_col_wrap )
类似地,我们可以按星期几对小费的小提琴图进行分面:
px.violin(
tips,="sex",
x="tip",
y="sex",
color="day",
facet_col=2,
facet_col_wrap )
分面图使我们能够比较不同日子的分布,提供更细致的见解。
10.8.4 练习题:小费分面图
使用 tips
数据集,创建一个按 day
分面、按 time
列百分比堆叠、颜色按 sex
列的条形图。
哪个日子的哪个时间段拥有最高比例的男性客户(例如,星期五午餐、星期六晚餐等)?
tips.head()# 您的代码在此处
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
10.9 总结
在本课程中,您学习了如何使用 Plotly Express 创建双变量和多变量图。理解这些可视化技术将帮助您更有效地探索和传达数据中的关系。
下节课见!