[英]How do I subdivide/refine a dimension in an xarray DataSet?
摘要:我有一个数据集,该数据集以维度最初不可用的方式收集。 我想获取本质上是一大块未区分数据的内容,并为其添加维度,以便可以对其进行查询、子集化等。这是以下问题的核心。
这是我拥有的一个 xarray 数据集:
<xarray.Dataset>
Dimensions: (chain: 1, draw: 2000, rows: 24000)
Coordinates:
* chain (chain) int64 0
* draw (draw) int64 0 1 2 3 4 5 6 7 ... 1993 1994 1995 1996 1997 1998 1999
* rows (rows) int64 0 1 2 3 4 5 6 ... 23994 23995 23996 23997 23998 23999
Data variables:
obs (chain, draw, rows) float64 4.304 3.985 4.612 ... 6.343 5.538 6.475
Attributes:
created_at: 2019-12-27T17:16:13.847972
inference_library: pymc3
inference_library_version: 3.8
这里的rows
维度对应于我需要恢复到数据的多个子维度。 特别是,这 24,000 行分别对应来自 240 个条件的 100 个样本(这 100 个样本位于连续块中)。 这些条件是gate
、 input
、 growth medium
和od
。
我想以这样的方式结束:
<xarray.Dataset>
Dimensions: (chain: 1, draw: 2000, gate: 1, input: 4, growth_medium: 3, sample: 100, rows: 24000)
Coordinates:
* chain (chain) int64 0
* draw (draw) int64 0 1 2 3 4 5 6 7 ... 1993 1994 1995 1996 1997 1998 1999
* rows *MultiIndex*
* gate (gate) int64 'AND'
* input (input) int64 '00', '01', '10', '11'
* growth_medium (growth_medium) 'standard', 'rich', 'slow'
* sample (sample) int64 0 1 2 3 4 5 6 7 ... 95 96 97 98 99
Data variables:
obs (chain, draw, gate, input, growth_medium, samples) float64 4.304 3.985 4.612 ... 6.343 5.538 6.475
Attributes:
created_at: 2019-12-27T17:16:13.847972
inference_library: pymc3
inference_library_version: 3.8
我有一个 Pandas 数据框,它指定了门、输入和生长培养基的值——每一行给出了一组门、输入和生长培养基的值,以及一个索引,指定了( rows
)对应的一组出现 100 个样本。 目的是该数据框是标记数据集的指南。
我查看了关于“重塑和重组数据”的 xarray 文档,但我没有看到如何组合这些操作来完成我需要的操作。 我怀疑我需要以某种方式将这些与GroupBy
结合起来,但我不明白如何。 谢谢!
后来:我有一个解决这个问题的方法,但它太恶心了,我希望有人解释我是多么错误,以及可能有什么更优雅的方法。
因此,首先,我将原始Dataset
中的所有数据提取为原始 numpy 形式:
foo = qm.idata.posterior_predictive['obs'].squeeze('chain').values.T
foo.shape # (24000, 2000)
然后我根据需要对其进行了改造:
bar = np.reshape(foo, (240, 100, 2000))
这给了我我想要的大致形状:有 240 个不同的实验条件,每个都有 100 个变体,对于这些变体中的每一个,我的数据集中有 2000 个蒙特卡罗样本。
现在,我从 Pandas DataFrame
提取有关 240 个实验条件的信息:
import pandas as pd
# qdf is the original dataframe with the experimental conditions and some
# extraneous information in other columns
new_df = qdf[['gate', 'input', 'output', 'media', 'od_lb', 'od_ub', 'temperature']]
idx = pd.MultiIndex.from_frame(new_df)
最后,我从 numpy 数组和 pandas MultiIndex
重新组装了一个DataArray
:
xr.DataArray(bar, name='obs', dims=['regions', 'conditions', 'draws'],
coords={'regions': idx, 'conditions': range(100), 'draws': range(2000)})
生成的DataArray
具有这些坐标,如我所愿:
Coordinates:
* regions (regions) MultiIndex
- gate (regions) object 'AND' 'AND' 'AND' 'AND' ... 'AND' 'AND' 'AND'
- input (regions) object '00' '10' '10' '10' ... '01' '01' '11' '11'
- output (regions) object '0' '0' '0' '0' '0' ... '0' '0' '0' '1' '1'
- media (regions) object 'standard_media' ... 'high_osm_media_five_percent'
- od_lb (regions) float64 0.0 0.001 0.001 ... 0.0001 0.0051 0.0051
- od_ub (regions) float64 0.0001 0.0051 0.0051 2.0 ... 0.0003 2.0 2.0
- temperature (regions) int64 30 30 37 30 37 30 37 ... 37 30 37 30 37 30 37
* conditions (conditions) int64 0 1 2 3 4 5 6 7 ... 92 93 94 95 96 97 98 99
* draws (draws) int64 0 1 2 3 4 5 6 ... 1994 1995 1996 1997 1998 1999
不过,这太可怕了,而且我必须通过xarray
抽象的所有漂亮层才能达到这一点似乎是错误的。 特别是因为这看起来不像是科学工作流程中的一个不寻常的部分:将相对原始的数据集与需要与数据结合的元数据电子表格一起获取。 那么我做错了什么? 什么是更优雅的解决方案?
给定起始数据集,类似于:
<xarray.Dataset>
Dimensions: (draw: 2, row: 24)
Coordinates:
* draw (draw) int32 0 1
* row (row) int32 0 1 2 3 4 5 6 7 8 9 ... 14 15 16 17 18 19 20 21 22 23
Data variables:
obs (draw, row) int32 0 1 2 3 4 5 6 7 8 ... 39 40 41 42 43 44 45 46 47
您可以连接几个纯 xarray 命令来细分维度(以相同的形状获取数据,但使用多索引)甚至重塑数据集。 要细分维度,可以使用以下代码:
multiindex_ds = ds.assign_coords(
dim_0=["a", "b", "c"], dim_1=[0,1], dim_2=range(4)
).stack(
dim=("dim_0", "dim_1", "dim_2")
).reset_index(
"row", drop=True
).rename(
row="dim"
)
multiindex_ds
其输出为:
<xarray.Dataset>
Dimensions: (dim: 24, draw: 2)
Coordinates:
* draw (draw) int32 0 1
* dim (dim) MultiIndex
- dim_0 (dim) object 'a' 'a' 'a' 'a' 'a' 'a' ... 'c' 'c' 'c' 'c' 'c' 'c'
- dim_1 (dim) int64 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
- dim_2 (dim) int64 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3
Data variables:
obs (draw, dim) int32 0 1 2 3 4 5 6 7 8 ... 39 40 41 42 43 44 45 46 47
此外,多索引然后可以被取消堆叠,有效地重塑数据集:
reshaped_ds = multiindex_ds.unstack("dim")
reshaped_ds
带输出:
<xarray.Dataset>
Dimensions: (dim_0: 3, dim_1: 2, dim_2: 4, draw: 2)
Coordinates:
* draw (draw) int32 0 1
* dim_0 (dim_0) object 'a' 'b' 'c'
* dim_1 (dim_1) int64 0 1
* dim_2 (dim_2) int64 0 1 2 3
Data variables:
obs (draw, dim_0, dim_1, dim_2) int32 0 1 2 3 4 5 ... 42 43 44 45 46 47
我认为仅凭这一点并不能完全满足您的需求,因为您想将一个维度转换为两个维度,其中一个维度是多索引。 不过,所有的构建块都在这里。
例如,您可以使用regions
和conditions
此步骤(包括拆垛),然后按照此步骤(现在不拆垛)将regions
转换为多索引。 另一种选择是从一开始就使用所有维度,将它们拆开,然后再次将它们堆叠起来,留下最终多索引之外的conditions
。
答案结合了几个非常不相关的命令,可能很难看到每个命令在做什么。
assign_coords
第一步是创建新的维度和坐标并将它们添加到数据集。 这是必要的,因为下一个方法需要维度和坐标已经存在于数据集中。
在assign_coords
之后assign_coords
停止assign_coords
产生以下数据集:
<xarray.Dataset>
Dimensions: (dim_0: 3, dim_1: 2, dim_2: 4, draw: 2, row: 24)
Coordinates:
* draw (draw) int32 0 1
* row (row) int32 0 1 2 3 4 5 6 7 8 9 ... 14 15 16 17 18 19 20 21 22 23
* dim_0 (dim_0) <U1 'a' 'b' 'c'
* dim_1 (dim_1) int32 0 1
* dim_2 (dim_2) int32 0 1 2 3
Data variables:
obs (draw, row) int32 0 1 2 3 4 5 6 7 8 ... 39 40 41 42 43 44 45 46 47
stack
数据集现在包含 3 个维度,总共有 24 个元素,但是,由于数据目前相对于这 24 个元素是平坦的,我们必须将它们堆叠成一个 24 元素的多索引,以使其形状兼容。
我发现assign_coords
后跟stack
是最自然的解决方案,但是,另一种可能性是生成一个多索引,类似于上面的做法,并直接使用多assign_coords
调用assign_coords
,从而使堆栈assign_coords
不必要。
此步骤将所有 3 个新维度合并为一个:
<xarray.Dataset>
Dimensions: (dim: 24, draw: 2, row: 24)
Coordinates:
* draw (draw) int32 0 1
* row (row) int32 0 1 2 3 4 5 6 7 8 9 ... 14 15 16 17 18 19 20 21 22 23
* dim (dim) MultiIndex
- dim_0 (dim) object 'a' 'a' 'a' 'a' 'a' 'a' ... 'c' 'c' 'c' 'c' 'c' 'c'
- dim_1 (dim) int64 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
- dim_2 (dim) int64 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3
Data variables:
obs (draw, row) int32 0 1 2 3 4 5 6 7 8 ... 39 40 41 42 43 44 45 46 47
请注意,根据需要,现在我们有 2 个尺寸为 24 的维度。
reset_index
现在我们在 Dataset 中将最终维度作为坐标存在,并且我们希望这个新坐标是用于索引变量obs
坐标。 set_index
似乎是正确的选择,但是,我们的每个坐标索引本身(与set_index
文档中的示例不同,其中x
索引x
和a
坐标)这意味着set_index
不能在这种特殊情况下使用。 使用的方法是reset_index
删除坐标row
而不删除维度row
。
在下面的输出中,可以看出现在row
是一个没有坐标的维度:
<xarray.Dataset>
Dimensions: (dim: 24, draw: 2, row: 24)
Coordinates:
* draw (draw) int32 0 1
* dim (dim) MultiIndex
- dim_0 (dim) object 'a' 'a' 'a' 'a' 'a' 'a' ... 'c' 'c' 'c' 'c' 'c' 'c'
- dim_1 (dim) int64 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
- dim_2 (dim) int64 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3
Dimensions without coordinates: row
Data variables:
obs (draw, row) int32 0 1 2 3 4 5 6 7 8 ... 39 40 41 42 43 44 45 46 47
rename
当前数据集几乎是最后一个,唯一的问题是obs
变量仍然具有row
维度而不是所需的维度: dim
。 它看起来并不是rename
预期用途,但它可以用来dim
以吸收row
,产生所需的最终结果(上面称为multiindex_ds
)。
再次, set_index
似乎是选择的方法,但是,如果使用set_index(row="dim")
而不是rename(row="dim")
,则多索引将折叠set_index(row="dim")
元组组成的索引:
<xarray.Dataset>
Dimensions: (draw: 2, row: 24)
Coordinates:
* draw (draw) int32 0 1
* row (row) object ('a', 0, 0) ('a', 0, 1) ... ('c', 1, 2) ('c', 1, 3)
Data variables:
obs (draw, row) int32 0 1 2 3 4 5 6 7 8 ... 39 40 41 42 43 44 45 46 47
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.