Увеличение размерности рентгеновского массива по координатам

Скажем, у меня есть следующий 2d-массив

>>> 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? Или, по крайней мере, какой подход самый быстрый / дешевый?


person keepAlive    schedule 06.09.2017    source источник


Ответы (2)


Поскольку в конечном итоге нам понадобится размер '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', вы получите желаемое трехмерное 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'
person Michael Delgado    schedule 14.09.2017
comment
выглядит многообещающе. - person keepAlive; 14.09.2017

На самом деле я собираюсь использовать этот грязный подход, но это просто не лучшего решения.

Во-первых, давайте превратим этот 2dl-массив в dict, сформированный на основе ключей кортежа.

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

Пространство, в котором расположены эти значения, формируется над следующим списком измерений: ['hobby', 'name', 'age']. Пусть назначит это

>>> space = ['hobby', 'name', 'age']

Затем можно использовать метод from_tuples из pandas MultiIndex для построения логической структуры наших данных.

>>> 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. И его также можно использовать для уменьшения размерности.

person keepAlive    schedule 06.09.2017