Как использовать функцию DataArray где () для назначения значения из другого DataArray на основе условий - PullRequest
2 голосов
/ 06 марта 2019

Я работаю с xarray, чтобы создать новый набор данных на основе условий значений из другого набора данных.

Входной объект набора данных ds_season по сезонам и имеет три измерения, как показано ниже.

    <xarray.Dataset>
    Dimensions:               (latitude: 106, longitude: 193, season: 4)
    Coordinates:
      * latitude              (latitude) float32 -39.2 -39.149525 ... -33.9
      * longitude             (longitude) float32 140.8 140.84792 ... 150.0
      * season                (season) object 'DJF' 'JJA' 'MAM' 'SON'
    Data variables:
        FFDI 95TH PERCENTILE  (season, latitude, longitude) float64 dask.array<shape=(4, 106, 193), chunksize=(4, 106, 193)>

Мне нужно создать новый набор данных, который имеет три измерения широты, долготы и времени. Широта и долгота должны иметь те же координаты, что и входной набор данных, а временные координаты должны быть днями более 10 лет.

Например, результирующий набор данных имеет вид:

<xarray.Dataset>
Dimensions:    (latitude: 106, longitude: 193, time: 3653)
Coordinates:
  * latitude   (latitude) float32 -39.2 -39.149525 ... -33.950478 -33.9
  * longitude  (longitude) float32 140.8 140.84792 140.89584 ... 149.95209 150.0
  * time       (time) datetime64[ns] 1972-01-01T00:00:00 1972-01-02T00:00:00 1972-01-03T00:00:00 ... 1981-12-30T00:00:00 1981-12-31T00:00:00
Data variables:
    FFDI 95TH PERCENTILE  (time, latitude, longitude) float64 dask.array<shape=(3653, 106, 193), chunksize=(3653, 106, 193)>

Переменная для дня должна совпадать с переменной для сезона, в который входит день. Это означает, что значения 1972-01-01, 1972-02-02 и 1972-02-28 должны иметь то же значение, что и значение сезон DJF имеет; и 1972-04-01, 1972-05-02 и 1972-05-31 должны иметь то же значение, что и сезон MAM.

Я думаю о функции where () набора данных, но понятия не имею, с чего начать. http://xarray.pydata.org/en/stable/generated/xarray.Dataset.where.html?highlight=where#xarray.Dataset.where

Ответы [ 2 ]

0 голосов
/ 17 марта 2019

Я согласен с Андреа, что создание набора данных с 3653 уникальными днями, который копирует только 4 различных сезонных значения, в целом неэффективно. Если вы дадите больше информации о ваших более широких целях для этого, возможно, мы можем предложить альтернативное решение.

Если вы действительно хотите это сделать, возможно, самый быстрый способ - использовать арифметику группового вещания xarray . В дальнейшем я буду предполагать, что ds - это имя второго набора данных в исходном сообщении (с размерами (latitude: 106, longitude: 193, time: 3653)). Тогда вы можете сделать это очень быстро, как

zeros = xr.zeros_like(ds)
filled_in = zeros.groupby('time.season') + ds_season

Это предположение вдохновлено тем, как мы обычно вычисляем аномалию из сезонной климатологии:

# original dataset with dimensions 'time'
ds = xr.open_dataset(...)
# climatology has dimension 'season'
ds_climatology = ds.groubpy('time.season').mean(dim='time') 
# anomaly has dimension 'time'
ds_anomaly = ds.groubpy('time.season') - ds_climatology
0 голосов
/ 14 марта 2019

Во-первых, заметка. Создание нового массива данных, копирующего одни и те же идентичные пространственные данные каждый день в течение 3 месяцев, может занять много места на диске без особого смысла. Я бы предпочел запрашивать сезонный массив данных каждый раз, когда вам нужны данные за определенный день. Однако, если вам действительно нужно выполнить эту операцию и ответить на ваш вопрос, я думаю, что самый простой способ сделать это:

  1. сначала создайте новый контейнер; np.ndarray - хорошая и аккуратная идея.
  2. Затем создайте индекс даты,
  3. запрос вашего оригинального сезона DataArray,
  4. и, наконец, создайте новый массив данных с измерением времени.

В следующем примере я создал сезонный массив данных для тестирования. Если я точно понял вашу проблему, вы сможете использовать свой оригинальный массив без особых изменений во второй части (с созданием foo).

Давай углубимся в это. Первый импорт:

import xarray as xr
import numpy as np
import pandas as pd

Создать пустой контейнер необходимого размера.

data_s = np.zeros((4, 10, 10))

Заполните его фиктивными значениями.

data_s[0] = 0.5
data_s[1] = 0.9
data_s[2] = 0.8
data_s[3] = 0.45

Создание фиктивных координат.

x = y = np.arange(10)

Создать индекс сезона.

seasons = ["spring", "summer", "autumn", "winter"]

Наконец, создайте массив данных.

bar = xr.DataArray(data_s, coords=[seasons, x, y], dims=['season', 'x', 'y'])

bar - это массив данных, из которого вы хотите извлечь сезонные значения. Теперь повторите то же самое для отдельных дат.

Создайте массив контейнеров на 2000 дней, который мы будем заполнять данными каждого сезона.

data = np.ones((2000, 10, 10))
x = y = np.arange(10)
dates = pd.date_range('2000-01-01', periods=2000)

Здесь я предполагаю, что бореальные сезоны начинаются с первого числа месяца (заимствовано из здесь . Конечно, вы можете легко написать лучшую функцию, например, используя день года, чтобы получить сезон.

season = np.array((dates.month %12 + 3)//3)

Создать словарь для преобразования приведенного числа в строку сезона, ранее назначенную в строке

seas_to_num = {1:"spring", 2:"summer", 3:"autumn", 4:"winter"}

Мы заполняем массив для каждого дня значениями, найденными в строке [сезон].

for date, seas in enumerate(season):
    data[date] = bar.sel(season=seas_to_num[seas])

Наконец, мы создаем массив данных.

foo = xr.DataArray(data, coords=[dates, x, y], dims=['time', 'x', 'y'])

Теперь, выбрав 5 апреля, мы получаем значение для весны.

In [1]: foo.sel(time=pd.to_datetime("5/4/2001"))
Out[1]: 
array([[0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9],
   [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9],
   [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9],
   [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9],
   [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9],
   [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9],
   [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9],
   [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9],
   [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9],
   [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9]])
Coordinates:
time     datetime64[ns] 2001-05-03
  * x        (x) int32 0 1 2 3 4 5 6 7 8 9
  * y        (y) int32 0 1 2 3 4 5 6 7 8 9
...