如何在xarray中合并具有不同尺寸大小的多个数据集(.h5文件)

时间:2019-12-11 14:54:30

标签: python-3.x python-xarray

我尝试了几种方法来从多个.h5文件中创建xarray(xr)数据集。这些文件包含来自SMAP项目的有关土壤水分含量的数据以及其他有用的变量。每个变量代表一个二维数组。每个文件中变量的数量及其标签均相等。问题是尺寸x和y的尺寸大小不相等。

Example dataset通过xr.open_dataset()加载

<xarray.Dataset>
Dimensions:                                     (x: 54, y: 129)
Coordinates:
    EASE_column_index_3km                       (x, y) float32 ...
    EASE_column_index_apm_3km                   (x, y) float32 ...
    EASE_row_index_3km                          (x, y) float32 ...
    EASE_row_index_apm_3km                      (x, y) float32 ...
    latitude_3km                                (x, y) float32 ...
    latitude_apm_3km                            (x, y) float32 ...
    longitude_3km                               (x, y) float32 ...
    longitude_apm_3km                           (x, y) float32 ...
Dimensions without coordinates: x, y
Data variables:
    SMAP_Sentinel_overpass_timediff_hr_3km      (x, y) timedelta64[ns] ...
    SMAP_Sentinel_overpass_timediff_hr_apm_3km  (x, y) timedelta64[ns] ...
    albedo_3km                                  (x, y) float32 ...
    albedo_apm_3km                              (x, y) float32 ...
    bare_soil_roughness_retrieved_3km           (x, y) float32 ...
    bare_soil_roughness_retrieved_apm_3km       (x, y) float32 ...
    beta_tbv_vv_3km                             (x, y) float32 ...
    beta_tbv_vv_apm_3km                         (x, y) float32 ...
    disagg_soil_moisture_3km                    (x, y) float32 ...
    disagg_soil_moisture_apm_3km                (x, y) float32 ...
    disaggregated_tb_v_qual_flag_3km            (x, y) float32 ...
    disaggregated_tb_v_qual_flag_apm_3km        (x, y) float32 ...
    gamma_vv_xpol_3km                           (x, y) float32 ...
    gamma_vv_xpol_apm_3km                       (x, y) float32 ...
    landcover_class_3km                         (x, y) float32 ...
    landcover_class_apm_3km                     (x, y) float32 ...
    retrieval_qual_flag_3km                     (x, y) float32 ...
    retrieval_qual_flag_apm_3km                 (x, y) float32 ...
    sigma0_incidence_angle_3km                  (x, y) float32 ...
    sigma0_incidence_angle_apm_3km              (x, y) float32 ...
    sigma0_vh_aggregated_3km                    (x, y) float32 ...
    sigma0_vh_aggregated_apm_3km                (x, y) float32 ...
    sigma0_vv_aggregated_3km                    (x, y) float32 ...
    sigma0_vv_aggregated_apm_3km                (x, y) float32 ...
    soil_moisture_3km                           (x, y) float32 ...
    soil_moisture_apm_3km                       (x, y) float32 ...
    soil_moisture_std_dev_3km                   (x, y) float32 ...
    soil_moisture_std_dev_apm_3km               (x, y) float32 ...
    spacecraft_overpass_time_seconds_3km        (x, y) timedelta64[ns] ...
    spacecraft_overpass_time_seconds_apm_3km    (x, y) timedelta64[ns] ...
    surface_flag_3km                            (x, y) float32 ...
    surface_flag_apm_3km                        (x, y) float32 ...
    surface_temperature_3km                     (x, y) float32 ...
    surface_temperature_apm_3km                 (x, y) float32 ...
    tb_v_disaggregated_3km                      (x, y) float32 ...
    tb_v_disaggregated_apm_3km                  (x, y) float32 ...
    tb_v_disaggregated_std_3km                  (x, y) float32 ...
    tb_v_disaggregated_std_apm_3km              (x, y) float32 ...
    vegetation_opacity_3km                      (x, y) float32 ...
    vegetation_opacity_apm_3km                  (x, y) float32 ...
    vegetation_water_content_3km                (x, y) float32 ...
    vegetation_water_content_apm_3km            (x, y) float32 ...
    water_body_fraction_3km                     (x, y) float32 ...
    water_body_fraction_apm_3km                 (x, y) float32 ...

示例变量数据集。soil_moisture_3km

<xarray.DataArray 'soil_moisture_3km' (x: 54, y: 129)>
array([[nan, nan, nan, ..., nan, nan, nan],
       [nan, nan, nan, ..., nan, nan, nan],
       [nan, nan, nan, ..., nan, nan, nan],
       ...,
       [nan, nan, nan, ..., nan, nan, nan],
       [nan, nan, nan, ..., nan, nan, nan],
       [nan, nan, nan, ..., nan, nan, nan]], dtype=float32)
Coordinates:
    EASE_column_index_3km      (x, y) float32 ...
    EASE_column_index_apm_3km  (x, y) float32 ...
    EASE_row_index_3km         (x, y) float32 ...
    EASE_row_index_apm_3km     (x, y) float32 ...
    latitude_3km               (x, y) float32 ...
    latitude_apm_3km           (x, y) float32 ...
    longitude_3km              (x, y) float32 ...
    longitude_apm_3km          (x, y) float32 ...
Dimensions without coordinates: x, y
Attributes:
    units:        cm**3/cm**3
    valid_min:    0.0
    long_name:    Representative soil moisture measurement for the 3 km Earth...
    coordinates:  /Soil_Moisture_Retrieval_Data_3km/latitude_3km /Soil_Moistu...
    valid_max:    0.75

首先,我尝试使用以下方式打开文件:

test = xr.open_mfdataset(list_of_paths)

发生此错误:

ValueError: arguments without labels along dimension 'x' cannot be aligned because they have different dimension sizes: {129, 132}

然后我尝试通过协调结合

test = xr.open_mfdataset(list_of_paths, combine='by_coords')

产生此错误:

ValueError: Could not find any dimension coordinates to use to order the datasets for concatenation

尝试一下:

test = xr.open_mfdataset(list_of_paths, coords=['latitude_3km', 'longitude_3km'], combine='by_coords')

以同样的错误结束。

然后,我尝试使用xr.open_dataset()打开每个文件,并尝试在documentation page上可以找到的用于合并数据的每种方法,例如合并,合并,broadcast_like,对齐和合并...,但是每次都结束同样存在尺寸不相等的问题。重塑,对齐尺寸的常用方法是什么?有什么可能解决此问题的方法?

更新:
我找到了解决该问题的方法,但首先我想我忘记提到了我尝试在维度时间内连接的不同文件具有不同的坐标和维度。我尝试从所有模型中构建的图像具有重叠的区域,这些区域具有相同的经度和纬度值,但部分区域也没有重叠。

2 个答案:

答案 0 :(得分:1)

  

每个文件中变量的数量及其标签均相等。问题是x和y的尺寸大小不相等。

抱歉,每个文件中的len(x)是否相同?和len(y)一样吗?否则open_mfdataset无法立即处理。

如果它们相同,则理论上您应该能够以两种不同的方式做到这一点。

那么,您将遇到一个2D串联问题:您需要对数据集进行排列,以使它们沿着x和y结合在一起时,会形成一个更大的数据集,同时具有x和y维度。

1)使用combine='nested'

您可以手动指定需要它们加入的顺序。xarray允许您通过将数据集作为网格(指定为嵌套列表)传递来进行此操作。在您的情况下,如果我们有4个文件(分别命名为[upper_left,upper_right,lower_left,lower_right]),则可以将它们组合为:

from xarray import open_mfdataset

grid = [[upper_left, upper_right], 
        [lower_left, lower_right]]

ds = open_mfdataset(grid, concat_dim=['x', 'y'], combine='nested')

我们不得不告诉open_mfdataset网格的行和列对应于数据的哪个维度,因此它将知道将数据串联在一起的维度。这就是为什么我们需要通过concat_dim=['x', 'y']

2)使用combine='by_coords'

但是您的数据中已经有坐标-xarray不能仅使用坐标来按正确的顺序排列数据集吗?这就是combine='by_coords'选项的作用,但是不幸的是,它需要一维坐标(也称为维坐标)来排列数据。您的文件没有任何文件(这就是打印输出显示Dimensions without coordinates: x, y的原因。)

如果您可以先向文件添加一维坐标,则可以使用combine='by_coords',然后可以按任何顺序传递所有文件的列表。但是否则,在这种情况下,您将不得不使用combine='nested'

(这里不需要coords参数,这与如何将不同的坐标结合在一起,而不是要使用的数据集的排列有关。)

答案 1 :(得分:0)

我的解决方法是,我根据所有.h5文件的唯一lon / lat值创建一个网格。

import xarray as xr

EASE_lat = list()
EASE_lon = list()

for file in files:
    ds = xr.open_dataset(file)
    lat = ds.latitude_3km.to_series().to_list()
    lon = ds.longitude_3km.to_series().to_list()
    EASE_lat.extend(lat)
    EASE_lon.extend(lon)


unique_lon = list(set(lon_list))
unique_lat = list(set(lat_list))

unique_lon_dim = np.arange(0,len(unique_lon),1).astype('float32')
unique_lat_dim = np.arange(0,len(unique_lat),1).astype('float32')

longitude_3km_coord = np.sort(np.array(unique_lon).astype('float32'))
latitude_3km_coord = np.sort(np.array(unique_lat).astype('float32'))

var_1, var_2 = np.meshgrid(latitude_3km_coord, longitude_3km_coord )
np.place(var_1, var_1 != 1, np.nan)
np.place(var_2, var_2 != 1, np.nan)

print('var_1', var_1.shape, 'dims: (lat/lon) ', unique_lon_dim.shape ,unique_lat_dim.shape , 'coords : (lon/lat)', longitude_3km_coord.shape, latitude_3km_coord.shape)

var_1: (237, 126) dims(lat/lon): (237,) (126,) coords (lon/lat) : (237,) (126,)

现在我可以创建基础数据集

init_ds_2v = xr.Dataset(
        data_vars={'soil_moisture_3km':    (('longitude_3km', 'latitude_3km'), var_1),
                   'radolan_3km': (('longitude_3km', 'latitude_3km'), var_2)},
        coords={'longitude_3km': longitude_3km_coord,
                'latitude_3km': latitude_3km_coord})

print(init_ds_2v)
<xarray.Dataset>
Dimensions:            (latitude_3km: 126, longitude_3km: 237)
Coordinates:
  * longitude_3km      (longitude_3km) float32 5.057054 5.0881743 ... 12.401452
  * latitude_3km       (latitude_3km) float32 47.54788 47.582508 ... 52.0727
Data variables:
    soil_moisture_3km  (longitude_3km, latitude_3km) float32 nan nan ... nan nan
    radolan_3km        (longitude_3km, latitude_3km) float32 nan nan ... nan nan

现在我可以将这些不相等的数据集与基本网格合并

compilation = ds.merge(init_ds_2v, compat='override')

我在预处理功能中执行此步骤,可以在openmfdataset函数中应用

def preprocess_SMAP_3km(ds):
    compilation = None
    filename = ds.encoding['source'][-74:]
    date = datetime.datetime.strptime(filename[21:29], '%Y%m%d')
    date = np.datetime64(date)
    ds['latitude_3km'] = ds['latitude_3km'][:,0] #-> 1d array
    ds['longitude_3km'] = ds['longitude_3km'][0,:] #-> 1d array
    #Set Coordinates for x(lon) and y(lat)
    ds = ds.rename_dims({'phony_dim_2' : 'latitude', 'phony_dim_3' : 'longitude'})
    ds = ds.swap_dims({'longitude' : 'longitude_3km', 'latitude' : 'latitude_3km'})
    ds = ds.set_coords(['latitude_3km' , 'longitude_3km'])
    ds = ds['soil_moisture_3km'].to_dataset()
    ds['time'] = date
    ds.expand_dims('time').set_coords('time')
    compilation = ds.merge(init_ds_2v, compat='override')
    print(compilation)
    return compilation

data = xr.open_mfdataset(files, preprocess=preprocess_SMAP_3km, concat_dim='time') 

我最终得到了这个数据集

<xarray.Dataset>
Dimensions:            (latitude_3km: 126, longitude_3km: 237, time: 1012)
Coordinates:
  * latitude_3km       (latitude_3km) float64 47.55 47.58 47.62 ... 52.03 52.07
  * longitude_3km      (longitude_3km) float64 5.057 5.088 5.119 ... 12.37 12.4
  * time               (time) datetime64[ns] 2015-04-01 ... 2019-11-30
Data variables:
    soil_moisture_3km  (time, latitude_3km, longitude_3km) float32 dask.array<chunksize=(1, 126, 237), meta=np.ndarray>
    radolan_3km        (time, longitude_3km, latitude_3km) float32 nan ... nan