从坐标增加 xarray 的维数
Increase Dimensionality of a xarray from coordinates
假设我有以下二维数组
>>> import numpy as np
>>> budgets = np.array([
[np.nan, 450.],
[500. , 100.],
[np.nan, 900.],
])
其值的位置是这样的
>>> coords = [
('name' , ['Jack_teen' , 'John_adult', 'John_teen']), # over rows
('hobby', ['books', 'bicyle']), # over columns
]
使用xarray我可以创建一个二维标记数组,做
>>> import xarray as xr
>>> x = xr.DataArray(budgets, coords=coords)
所以约翰在十几岁的时候就不喜欢书了,这在那个时候有预算是可以看得出来的
>>> x.sel(name='John_teen', hobby='books')
<xarray.DataArray ()>
array(nan)
Coordinates:
name |S10 'John_teen'
hobby |S6 'books'
随着年龄的增长发生了什么变化
>>> x.sel(name='John_adult', hobby='books')
<xarray.DataArray ()>
array(500.0)
Coordinates:
name |S10 'John_adult'
hobby |S6 'books'
我的问题:
你如何将这个 2dl 数组变成一个 3dl 数组,它考虑一个名为 age
的新维度(其坐标因此是 ['adult','teen'])
,同时简化维度 name
?
注意 name
的坐标总是 结构,下划线分隔,我的意思是 NAME_AGE.当然,您开始执行此操作的对象是 x
.
是否有 xarray-builtin 方式来做到这一点?或者至少 fastest/cheapest 方法是什么?
其实,这种肮脏的做法是我要做的,但这只是不能是最好的解决方案。
首先,让我们将这个 2dl 数组变成一个由元组键组成的字典。
dict_ = {}
for hobby in x['hobby'].data:
for name_age in x['name'].data:
name,age = name_age.split('_')
dict_[(hobby, name, age,)] = x.sel(name=name_age, hobby=hobby).data
这些值所在的 space 由以下维度列表组成:['hobby', 'name', 'age']
。赋值吧
>>> space = ['hobby', 'name', 'age']
然后,可以使用 pandas's MultiIndex 对象的方法 from_tuples
来构建我们数据的布尔定位结构
>>> import pandas as pd
>>> index = pd.MultiIndex.from_tuples(dict_.keys(), names=space)
最后,
>>> hyper_x = pd.Series(dict_, index=index).to_xarray()
因此
>>> hyper_x.sel(name='John', age='teen', hobby='books')
<xarray.DataArray ()>
array(nan)
Coordinates:
hobby |S5 'books'
name |S4 'John'
age |S4 'teen'
>>> hyper_x.sel(name='John', age='adult', hobby='books')
<xarray.DataArray ()>
array(500.0)
Coordinates:
hobby |S5 'books'
name |S4 'John'
age |S5 'adult'
这种方法的优点是它可以很容易地推广到任意数量的维度,无论是 x
还是 hyper_x
。而且它也可以用来降维。
由于我们最终想要一个维度 'name'
,我将把当前的 'name'
重命名为 'name_age'
:
In [5]: x = x.rename({'name': 'name_age'})
我们可以直接从坐标值构造一个 MultiIndex
并将其指定为堆叠 DataArray
坐标:
In [6]: x.coords['name_age'] = pd.MultiIndex.from_tuples(
...: [tuple(s.split('_')) for s in x.coords['name_age'].values],
...: names=['name', 'age'])
In [7]: x
Out[7]:
<xarray.DataArray (name_age: 3, hobby: 2)>
array([[ nan, 450.],
[ 500., 100.],
[ nan, 900.]])
Coordinates:
* name_age (name_age) MultiIndex
- name (name_age) object 'Jack' 'John' 'John'
- age (name_age) object 'teen' 'adult' 'teen'
* hobby (hobby) |S6 'books' 'bicyle'
如果您随后展开 'name_age'
,您将获得所需的 3-D DataArray
:
In [8]: x.unstack('name_age')
Out[8]:
<xarray.DataArray (hobby: 2, name: 2, age: 2)>
array([[[ nan, nan],
[ 500., nan]],
[[ nan, 450.],
[ 100., 900.]]])
Coordinates:
* hobby (hobby) |S6 'books' 'bicyle'
* name (name) object 'Jack' 'John'
* age (age) object 'adult' 'teen'
假设我有以下二维数组
>>> import numpy as np
>>> budgets = np.array([
[np.nan, 450.],
[500. , 100.],
[np.nan, 900.],
])
其值的位置是这样的
>>> coords = [
('name' , ['Jack_teen' , 'John_adult', 'John_teen']), # over rows
('hobby', ['books', 'bicyle']), # over columns
]
使用xarray我可以创建一个二维标记数组,做
>>> import xarray as xr
>>> x = xr.DataArray(budgets, coords=coords)
所以约翰在十几岁的时候就不喜欢书了,这在那个时候有预算是可以看得出来的
>>> x.sel(name='John_teen', hobby='books')
<xarray.DataArray ()>
array(nan)
Coordinates:
name |S10 'John_teen'
hobby |S6 'books'
随着年龄的增长发生了什么变化
>>> x.sel(name='John_adult', hobby='books')
<xarray.DataArray ()>
array(500.0)
Coordinates:
name |S10 'John_adult'
hobby |S6 'books'
我的问题:
你如何将这个 2dl 数组变成一个 3dl 数组,它考虑一个名为 age
的新维度(其坐标因此是 ['adult','teen'])
,同时简化维度 name
?
注意 name
的坐标总是 结构,下划线分隔,我的意思是 NAME_AGE.当然,您开始执行此操作的对象是 x
.
是否有 xarray-builtin 方式来做到这一点?或者至少 fastest/cheapest 方法是什么?
其实,这种肮脏的做法是我要做的,但这只是不能是最好的解决方案。
首先,让我们将这个 2dl 数组变成一个由元组键组成的字典。
dict_ = {}
for hobby in x['hobby'].data:
for name_age in x['name'].data:
name,age = name_age.split('_')
dict_[(hobby, name, age,)] = x.sel(name=name_age, hobby=hobby).data
这些值所在的 space 由以下维度列表组成:['hobby', 'name', 'age']
。赋值吧
>>> space = ['hobby', 'name', 'age']
然后,可以使用 pandas's MultiIndex 对象的方法 from_tuples
来构建我们数据的布尔定位结构
>>> import pandas as pd
>>> index = pd.MultiIndex.from_tuples(dict_.keys(), names=space)
最后,
>>> hyper_x = pd.Series(dict_, index=index).to_xarray()
因此
>>> hyper_x.sel(name='John', age='teen', hobby='books')
<xarray.DataArray ()>
array(nan)
Coordinates:
hobby |S5 'books'
name |S4 'John'
age |S4 'teen'
>>> hyper_x.sel(name='John', age='adult', hobby='books')
<xarray.DataArray ()>
array(500.0)
Coordinates:
hobby |S5 'books'
name |S4 'John'
age |S5 'adult'
这种方法的优点是它可以很容易地推广到任意数量的维度,无论是
x
还是 hyper_x
。而且它也可以用来降维。
由于我们最终想要一个维度 'name'
,我将把当前的 'name'
重命名为 'name_age'
:
In [5]: x = x.rename({'name': 'name_age'})
我们可以直接从坐标值构造一个 MultiIndex
并将其指定为堆叠 DataArray
坐标:
In [6]: x.coords['name_age'] = pd.MultiIndex.from_tuples(
...: [tuple(s.split('_')) for s in x.coords['name_age'].values],
...: names=['name', 'age'])
In [7]: x
Out[7]:
<xarray.DataArray (name_age: 3, hobby: 2)>
array([[ nan, 450.],
[ 500., 100.],
[ nan, 900.]])
Coordinates:
* name_age (name_age) MultiIndex
- name (name_age) object 'Jack' 'John' 'John'
- age (name_age) object 'teen' 'adult' 'teen'
* hobby (hobby) |S6 'books' 'bicyle'
如果您随后展开 'name_age'
,您将获得所需的 3-D DataArray
:
In [8]: x.unstack('name_age')
Out[8]:
<xarray.DataArray (hobby: 2, name: 2, age: 2)>
array([[[ nan, nan],
[ 500., nan]],
[[ nan, 450.],
[ 100., 900.]]])
Coordinates:
* hobby (hobby) |S6 'books' 'bicyle'
* name (name) object 'Jack' 'John'
* age (age) object 'adult' 'teen'