Fork me on GitHub

Seaborn教程之数据结构(三)

一、Seaborn接受的数据结构

作为一个数据可视化库,seaborn 需要你为它提供数据。。Seaborn 支持多种不同的数据集格式,并且大多数函数都接受用pandasnumpy库中的对象以及列表和字典等内置 Python 类型表示的数据。

对于数据格式,主要有两种:

  • 长格式
  • 宽格式

seaborn 中的大多数绘图函数都是面向数据向量的。当针对 绘制xy,每个变量都应该是一个向量。Seaborn 接受具有以某种表格方式组织的多个向量的数据集。“长格式”和“宽格式”数据表之间存在根本区别,seaborn 将以不同方式对待它们。

(一)长格式数据

长格式数据表具有以下特点:

  • 每个变量是一列
  • 每个观察都是一行

举个简单的例子,考虑“航班”数据集,它记录了从 1949 年到 1960 年每个月乘坐飞机的航空公司乘客数量。该数据集具有三个变量(乘客数量):

flights = sns.load_dataset("flights")
flights.head()
year month passengers
0 1949 Jan 112
1 1949 Feb 118
2 1949 Mar 132
3 1949 Apr 129
4 1949 May 121

对于长格式数据,表中的列通过显式分配给其中一个变量来在图中扮演角色。例如,绘制每年乘客数量的月图如下所示:

sns.relplot(data=flights, x="year", y="passengers", hue="month", kind="line")

长格式数据的优势在于它非常适合这种明确的场景。它可以容纳任意复杂的数据集,只要可以明确定义变量和观察值即可。但是这种格式需要进行处理,因为它通常不是人们头脑中的数据模型。

(二)宽格式数据

对于简单的数据集,以在电子表格中查看数据的方式来考虑数据通常更直观,其中列和行包含不同变量的水平。例如,我们可以通过“pivoting”将航班数据集转换为宽型组织,以便每一列都有多年来的每个月的时间序列:

flights_wide = flights.pivot(index="year", columns="month", values="passengers")
flights_wide.head()
month Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
year
1949 112 118 132 129 121 135 148 148 136 119 104 118
1950 115 126 141 135 125 149 170 170 158 133 114 140
1951 145 150 178 163 172 178 199 199 184 162 146 166
1952 171 180 193 181 183 218 230 242 209 191 172 194
1953 196 196 236 235 229 243 264 272 237 211 180 201

这里我们有相同的三个变量,但它们的组织方式不同。此数据集中的变量是表的维度(year、month),而不是命名字段。每个观察值都由表中单元格的值和该单元格相对于行和列索引的坐标定义。

对于长格式数据,我们可以通过名称访问数据集中的变量。宽格式数据不是这种情况。尽管如此,由于表的维度与数据集中的变量之间存在明确的关联,因此 seaborn 能够在图中分配这些变量的角色。

sns.relplot(data=flights_wide, kind="line")

Seaborn 已将数据索引分配给 x,将数据值分配给y,并且它为每个月绘制了一条单独的线。显然当数据集经历将其从长格式转换为宽格式的“透视”操作时,有关值含义的信息丢失了。因此,没有 y 轴标签。

长格式数据的一大优点是,一旦你拥有正确格式的数据,你就不再需要考虑它的结构。您可以通过仅考虑其中包含的变量来设计您的图。例如,要绘制代表每年每月时间序列的线,只需重新分配变量:

sns.relplot(data=flights, x="month", y="passengers", hue="year", kind="line")

为了使用宽格式数据集实现相同的效果,我们需要转置表格:

sns.relplot(data=flights_wide.transpose(), kind="line")

二、长格式选项

虽然长格式数据有一个精确的定义,但就如何在内存中的数据结构中实际组织而言,seaborn 相当灵活。文档其余部分中的示例通常会pandas.DataFrame通过将列的名称分配给图中的变量来使用其中的对象和引用变量。但也可以将向量存储在 Python 字典或实现该接口的类中:

flights_dict = flights.to_dict()
sns.relplot(data=flights_dict, x="year", y="passengers", hue="month", kind="line")

许多 pandas 操作,例如 group-by 的拆分-应用-组合操作,将生成一个数据框,其中信息已从输入数据框的列移动到输出的索引。只要保留名称,您仍然可以正常引用数据:

flights_avg = flights.groupby("year").mean()
sns.relplot(data=flights_avg, x="year", y="passengers", kind="line")

此外,可以将数据向量作为参数直接传递给xy和其他绘图变量。如果这些向量是 pandas 对象,则该name属性将用于标记绘图:

year = flights_avg.index
passengers = flights_avg["passengers"]
sns.relplot(x=year, y=passengers, kind="line")

实现 Python 序列接口的 Numpy 数组和其他对象也可以工作,但如果它们没有名称,如果不进一步调整,绘图将不会提供足够的信息:

sns.relplot(x=year.to_numpy(), y=passengers.to_list(), kind="line")

三、宽格式选项

传递宽格式数据的选项更加灵活。与长格式数据一样,pandas 对象更可取,因为可以使用名称(在某些情况下还可以使用索引)信息。但本质上,任何可以被视为单个向量或向量集合的格式都可以传递给data,并且通常可以构建有效的绘图。

我们在上面看到的例子使用了一个pandas.DataFrame,它可以被认为是它的列的集合。字典或 pandas 对象列表也可以,但我们会丢失轴标签:

flights_wide_list = [col for _, col in flights_wide.items()]
sns.relplot(data=flights_wide_list, kind="line")

集合中的向量不需要具有相同的长度。如果他们有一个index,它将被用来对齐他们:

two_series = [flights_wide.loc[:1955, "Jan"], flights_wide.loc[1952:, "Aug"]]
sns.relplot(data=two_series, kind="line")

而序号索引将用于 numpy 数组或简单的 Python 序列:

two_arrays = [s.to_numpy() for s in two_series]
sns.relplot(data=two_arrays, kind="line")

two_arrays = [array([112, 115, 145, 171, 196, 204, 242], dtype=int64), array([347, 405, 467, 505, 559, 606], dtype=int64)]

但是此类向量的字典至少会使用键:

two_arrays_dict = {s.name: s.to_numpy() for s in two_series}
sns.relplot(data=two_arrays_dict, kind="line")

two_arrays_dict =

矩形 numpy 数组被视为没有索引信息的数据框,因此它们被视为列向量的集合。请注意,这与 numpy 索引操作的工作方式不同,其中单个索引器将访问一行。但这与 pandas 如何将数组转换为数据框或 matplotlib 如何绘制它是一致的:

flights_array = flights_wide.to_numpy()
sns.relplot(data=flights_array, kind="line")

flights_array = [[112 118 132 129 121 135 148 148 136 119 104 118][115 126 141 135 125 149 170 170 158 133 114 140][145 150 178 163 172 178 199 199 184 162 146 166][171 180 193 181 183 218 230 242 209 191 172 194][196 196 236 235 229 243 264 272 237 211 180 201][204 188 235 227 234 264 302 293 259 229 203 229][242 233 267 269 270 315 364 347 312 274 237 278][284 277 317 313 318 374 413 405 355 306 271 306][315 301 356 348 355 422 465 467 404 347 305 336][340 318 362 348 363 435 491 505 404 359 310 337][360 342 406 396 420 472 548 559 463 407 362 405][417 391 419 461 472 535 622 606 508 461 390 432]]

posted @ 2023-01-19 10:13  iveBoy  阅读(417)  评论(0)    收藏  举报
TOP