Python 如何将带有complex128数据的xarray.DataArray保存到netcdf

Python 如何将带有complex128数据的xarray.DataArray保存到netcdf,python,netcdf4,xarray,Python,Netcdf4,Xarray,我在xarray数据集中有一些复杂的数据(numpy dtype complex128),我想用它保存到_netcdf。我得到以下错误: TypeError: illegal primitive data type, must be one of dict_keys(['S1', 'i1', 'u1', 'i2', 'u2', 'i4', 'u4', 'i8', 'u8', 'f4', 'f8']), got complex128 我知道我正在向底层netCDF4传递一个不受支持的数据类型。我

我在xarray数据集中有一些复杂的数据(numpy dtype complex128),我想用它保存到_netcdf。我得到以下错误:

TypeError: illegal primitive data type, must be one of dict_keys(['S1', 'i1', 'u1', 'i2', 'u2', 'i4', 'u4', 'i8', 'u8', 'f4', 'f8']), got complex128
我知道我正在向底层netCDF4传递一个不受支持的数据类型。我还发现了netcdf4的复合数据类型。但不幸的是,我不知道如何将其应用于我的问题,因为我没有直接使用netcdf4库

我是否可以在保留数据类型(使用
xarray.DataArray.to_netcdf
)的同时将数据类型complex128的数据保存到netcdf

MWE:


NetCDF作为文件格式不支持复杂数据。显然,地球科学用户不太需要保存复杂的值

也就是说,您确实可以使用某种特殊约定(例如使用自定义复合数据类型)将complex128数据写入netCDF文件。这与h5py使用的方法类似。这确实需要在xarray本身中实现:pull请求是受欢迎的

对于当前版本的xarray,您有两个用于序列化复杂值的选项:

  • 使用
    engine='h5netcdf'
    。这使用h5py的约定来编写复杂数据。不幸的是,这会导致无效的netCDF文件,该文件是无效的。 如果您尝试,应该会看到一条警告消息指示这一点。在xarray的未来版本中,我们可能需要使用专门的方法,例如
    到_hdf5()
    而不是
    到_netcdf()
    来创建此类无效文件

  • 将数据转换为实部和虚部,并将它们保存为单独的变量。从磁盘读回数据时,将它们重新组合为复杂值。选择你认为最好的特别会议

  • e、 g


    除了shoyer提供的两个非常好的选项之外,我发现还有另一个在实践中非常有用的解决方案:

    将另一个长度为2的维度添加到数据集中,该维度表示数据的实部和虚部。这类似于将实部和虚部存储在单独的变量中,但根据我的经验,在某些情况下使用起来会更好

    例如,存储,例如,代码<浮标< /C>变量,其尺寸为<代码>(x,ReIm)< /> >,其中<代码> ReIm < /C> >是虚构的,代码< >代码>任意维,给出了一个与C中的维度<代码> x<代码>相当的一维内存布局,或者等效地, STD::C++中的复杂< /COD> > 阅读和写作这样的作品:

    def save_complex(dataset, *args, **kwargs):
        ds = dataset.expand_dims('ReIm', axis=-1) # Add ReIm axis at the end
        ds = xarray.concat([ds.real, ds.imag], dim='ReIm')
        return ds.to_netcdf(*args, **kwargs)
    
    def read_complex(*args, **kwargs):
        ds = xarray.open_dataset(*args, **kwargs)
        return ds.isel(ReIm=0) + 1j * ds.isel(ReIm=1)
    

    如示例所示,这种方法对于数据集(不仅仅是数据数组)很容易实现。

    尽管我更喜欢您的方法,即增加真实/复杂的维度,而不是添加第二个变量(如@shoyer的答案),但您的解决方案似乎需要更多的内存(?)。虽然shoyer的解决方案可以很好地处理测试数据集(~2GB),但您的解决方案内存不足。谢谢你的主意!:)
    def save_complex(data_array, *args, **kwargs):
        ds = xarray.Dataset({'real': data_array.real, 'imag': data_array.imag})
        return ds.to_netcdf(*args, **kwargs)
    
    def read_complex(*args, **kwargs):
        ds = xarray.open_dataset(*args, **kwargs)
        return ds['real'] + ds['imag'] * 1j
    
    def save_complex(dataset, *args, **kwargs):
        ds = dataset.expand_dims('ReIm', axis=-1) # Add ReIm axis at the end
        ds = xarray.concat([ds.real, ds.imag], dim='ReIm')
        return ds.to_netcdf(*args, **kwargs)
    
    def read_complex(*args, **kwargs):
        ds = xarray.open_dataset(*args, **kwargs)
        return ds.isel(ReIm=0) + 1j * ds.isel(ReIm=1)