Преобразование серии xarray.DataArrays в массив NumPy

Я использую пакет под названием PySD для моделирования системной динамики. PySD преобразует модели из Vensim (пакет моделирования системной динамики) в python и позволяет пользователю заменять различные уравнения более сложными процедурами, чем Vensim. Я использую модель со множеством подписчиков, и это создает необычный формат выходных данных. Выходные данные считываются во фрейм данных, индивидуальные значения для подписанных элементов заканчиваются xarray.DataArrays. Мне интересно, как взять столбец xarray.DataArrays (который в конечном итоге является серией) и преобразовать его в двумерный массив со вторым измерением, являющимся числом индексов.

import pysd
import numpy as np

model=pysd.load("Example.py")
stocks=model.run
pop=np.array(Population) #Creates an object array
Population=stocks.Populaton #Creates a series

#How to get an array of population values for each country?

Код example.py выглядит следующим образом (имейте в виду, что это произвольный пример для иллюстрации проблемы)

from __future__ import division
import numpy as np
from pysd import utils
import xarray as xr

from pysd.functions import cache
from pysd import functions

_subscript_dict = {
    'Country': ['Canada', 'USA', 'China', 'Norway', 'India', 'England', 
'Mexico', 'Yemen']
}

_namespace = {   
    'TIME': 'time',
    'Time': 'time',
    'Deaths': 'deaths',
    'Births': 'births',
    'Population': 'population',
    'Birth rate': 'birth_rate',
    'Murder rate': 'murder_rate',
    'Natural death rate': 'natural_death_rate',
    'FINAL TIME': 'final_time',
    'INITIAL TIME': 'initial_time',
    'SAVEPER': 'saveper',
    'TIME STEP': 'time_step'
}

@cache('step')
def deaths():

    return murder_rate() * population() + natural_death_rate() * population()


@cache('step')
def births():
    return birth_rate() * population()


@cache('step')
def population():
    return integ_population()


@cache('run')
def birth_rate():

    return utils.xrmerge([
        xr.DataArray(
            data=[5., 5., 5., 5., 5., 5., 5., 5.],
            coords={
                'Country':
                ['Canada', 'USA', 'China', 'Norway', 'India', 'England', 'Mexico', 'Yemen']
            },
            dims=['Country']),
        xr.DataArray(data=[10.], coords={'Country': ['Mexico']}, dims=
['Country']),
        xr.DataArray(data=[8.], coords={'Country': ['Yemen']}, dims=
['Country']),
    ])


@cache('step')
def murder_rate():
    return time()


@cache('run')
def natural_death_rate():
    return utils.xrmerge([
        xr.DataArray(
            data=[3., 3., 3., 3., 3., 3., 3., 3.],
            coords={
                'Country':
                ['Canada', 'USA', 'China', 'Norway', 'India', 'England', 'Mexico', 'Yemen']
            },
            dims=['Country']),
        xr.DataArray(data=[5.], coords={'Country': ['Yemen']}, dims=['Country']),
    xr.DataArray(data=[5.], coords={'Country': ['Mexico']}, dims=['Country']),
    ])


@cache('run')
def final_time():
    return 100


@cache('run')
def initial_time():
    return 0


@cache('step')
def saveper():
    return time_step()


@cache('run')
def time_step():
    return 1


def _init_population():
    return xr.DataArray(
        data=np.ones([8]) * 10,
        coords={
            'Country': ['Canada', 'USA', 'China', 'Norway', 'India', 'England', 'Mexico', 'Yemen']
        },
        dims=['Country'])


@cache('step')
def _dpopulation_dt():
    return births() - deaths()


integ_population = functions.Integ(lambda: _dpopulation_dt(), lambda: _init_population())

Приношу свои извинения, если вкладки файла example.py не совпадают. Любая помощь будет оценена!

1 ответ

Решение

Спасибо, что поделились примером того, как эти данные выглядят.

Прежде всего, вложенность xarray.DataArray объекты как скаляры внутри pandas.DataFrame это весьма нестандартный способ работы с xarray и пандами. Я не рекомендую это. Если каждая запись представляет собой массив данных DataArray, который разделяет (некоторые из них) одни и те же измерения, самый простой способ работы с вашими данными - это xarray.DatasetXarray-версия многомерного pandas.DataFrame,

Тем не менее, должно быть просто преобразовать ваши данные из этого формата в неопубликованные объекты, с которыми легче работать. Лучшее место для начала с Series.values, который извлекает столбец в виде 1-мерного массива. Затем вы можете перебрать ряд и преобразовать каждый DataArray в массиве с .values, тоже. Собираем это вместе:

population_numpy_array = np.stack(
    [data_array.values for data_array in df['Population'].values])

Кроме того, вы можете сложить объекты DataArray с помощью xarray. Это сохранит метки, которые облегчат работу с вашими данными:

population_data_array = xr.concat(df['Population'].values, dim='row_name')

Вы можете даже превратить ваш полный объект в xarray.Dataset для совместного анализа:

ds = xr.Dataset({k: xr.concat(df[k].values, dim='row_name') for k in df.keys()})

(Возможно, именно это и должен делать PySD.)

Другие вопросы по тегам