【问题标题】:Creating a new NetCDF from existing NetCDF file while preserving the compression of the original file从现有的 NetCDF 文件创建新的 NetCDF,同时保留原始文件的压缩
【发布时间】:2018-07-23 04:23:09
【问题描述】:

我正在尝试从现有的 NetCDF 文件创建一个新的 NetCDF 文件。我只对使用 177 个变量列表中的 12 个变量感兴趣。您可以从这个 ftp 站点 here 找到示例 NetCDF 文件。

我使用了之前 SO 答案中的以下代码。你可以找到它here

import netCDF4 as nc

file1 = '/media/sf_jason2/cycle_001/JA2_GPN_2PdP001_140_20080717_113355_20080717_123008.nc'
file2 = '/home/sandbox/test.nc'

toinclude = ['lat_20hz', 'lon_20hz', 'time_20hz', 'alt_20hz', 'ice_range_20hz_ku', 'ice_qual_flag_20hz_ku', 'model_dry_tropo_corr', 'model_wet_tropo_corr', 'iono_corr_gim_ku', 'solid_earth_tide', 'pole_tide', 'alt_state_flag_ku_band_status']

with nc.Dataset(file1) as src, nc.Dataset(file2, "w") as dst:
    # copy attributes
    for name in src.ncattrs():
        dst.setncattr(name, src.getncattr(name))
    # copy dimensions
    for name, dimension in src.dimensions.iteritems():
        dst.createDimension(
        name, (len(dimension) if not dimension.isunlimited else None))
    # copy all file data for variables that are included in the toinclude list
    for name, variable in src.variables.iteritems():
        if name in toinclude:
            x = dst.createVariable(name, variable.datatype, variable.dimensions)
            dst.variables[name][:] = src.variables[name][:]

我遇到的问题是原始文件只有 5.3 MB,但是当我在新文件上复制新变量时,大小约为 17 MB。剥离变量的全部目的是减小文件大小,但我最终会得到更大的文件大小。

我也尝试过使用 xarray。但是当我尝试合并多个变量时遇到问题。以下是我试图在 xarray 中实现的代码。

import xarray as xr

fName = '/media/sf_jason2/cycle_001/JA2_GPN_2PdP001_140_20080717_113355_20080717_123008.nc'
file2 = '/home/sandbox/test.nc'
toinclude = ['lat_20hz', 'lon_20hz', 'time_20hz', 'alt_20hz', 'ice_range_20hz_ku', 'ice_qual_flag_20hz_ku', 'model_dry_tropo_corr', 'model_wet_tropo_corr', 'iono_corr_gim_ku', 'solid_earth_tide', 'pole_tide', 'alt_state_flag_ku_band_status']

ds = xr.open_dataset(fName)
newds = xr.Dataset()
newds['lat_20hz'] = ds['lat_20hz']
newds.to_netcdf(file2)

如果我尝试复制一个变量,Xarray 可以正常工作,但是,当我尝试将多个变量复制到一个空数据集时,它会出现问题。我找不到任何使用 xarray 复制多个变量的好例子。无论哪种方式,我都很好地实现了这个工作流程。

最后,如何减小使用 netCDF4 创建的新 NetCDF 的文件大小?如果这不理想,有没有办法将多个变量添加到 xarray 中的空数据集而不会出现合并问题?

【问题讨论】:

  • 一定要用 Python 吗?如果没有,NCO 是处理这种情况的好工具。

标签: python netcdf python-xarray


【解决方案1】:

如果您使用的是 netCDF4 python 包,那么您可以使用 netcdf-c 库中的命令行工具。例如nccopy 允许从一个 netCDF 文件复制到另一个 netCDF 文件过滤变量:

$ VARS = "lat_20hz,lon_20hz,time_20hz,alt_20hz,ice_range_20hz_ku,ice_qual_flag_20hz_ku,model_dry_tropo_corr,model_wet_tropo_corr,iono_corr_gim_ku,solid_earth_tide,pole_tide,alt_state_flag_ku_band_status"
$ nccopy -V $VARS JA2_GPN_2PdP001_140_20080717_113355_20080717_123008.nc dum.nc

生成的文件dum.nc 将具有唯一需要的变量,并且它的大小将成比例。输出格式将与输入相同,在本例中为 classic 或 netCDF3。可以选择netCDF4-classic模型格式:

$ nccopy -k4 -V $VARS JA2_GPN_2PdP001_140_20080717_113355_20080717_123008.nc dum_k4.nc

这会产生更多的大小开销(

$ nccopy -k4 -s -d9 -V $VARS JA2_GPN_2PdP001_140_20080717_113355_20080717_123008.nc dum_k4_s_d9.nc

哪个大小将仅为前一个的 33%。

[ 编辑:这是从原始文件复制到新文件的命令,带有放气选项,没有变量过滤器: $ nccopy -k4 -s -d9 JA2_GPN_2PdP001_140_20080717_113355_20080717_123008.nc orig_k4_s_d9.nc ]

这里有不同文件的文件大小进行比较:

   Size File
5514208 JA2_GPN_2PdP001_140_20080717_113355_20080717_123008.nc
2579535 orig_k4_s_d9.nc
1494174 dum_k4.nc
1457076 dum.nc
 487695 dum_k4_s_d9.nc

nco 还有其他基于 bit-shavingscale-offset 的压缩有损算法。

查看nccopy -h 命令帮助。

【讨论】:

    【解决方案2】:

    您的原始文件格式是 NETCDF3_CLASSIC,但您的副本是 NETCDF4_CLASSIC。这增加了生成的文件大小,不知道为什么,但我以前遇到过这种情况。

    with nc.Dataset(file1) as src, nc.Dataset(file2, "w") as dst:
    

    到:

    with nc.Dataset(file1) as src, nc.Dataset(file2, "w", format="NETCDF3_CLASSIC") as dst:
    

    由于某种我不知道的原因,这导致您检查无限维度时出现问题,这也很容易解决。

    我修改后的脚本如下。生成的 NetCDF 文件为 1.4 MB

    import netCDF4 as nc
    
    file1 = 'JA2_GPN_2PdP001_140_20080717_113355_20080717_123008.nc'
    file2 = 'test.nc'
    
    toinclude = ['lat_20hz', 'lon_20hz', 'time_20hz', 'alt_20hz', 'ice_range_20hz_ku', 'ice_qual_flag_20hz_ku', 'model_dry_tropo_corr', 'model_wet_tropo_corr', 'iono_corr_gim_ku', 'solid_earth_tide', 'pole_tide', 'alt_state_flag_ku_band_status']
    
    with nc.Dataset(file1) as src, nc.Dataset(file2, "w", format="NETCDF3_CLASSIC") as dst:
     # copy attributes
      for name in src.ncattrs():
        dst.setncattr(name, src.getncattr(name))
      # copy dimensions
      for name, dimension in src.dimensions.iteritems():
        if dimension.isunlimited():
          dst.createDimension( name, None)
        else:
          dst.createDimension( name, len(dimension))
      # copy all file data for variables that are included in the toinclude list
      for name, variable in src.variables.iteritems():
        if name in toinclude:
          x = dst.createVariable(name, variable.datatype, variable.dimensions)
          dst.variables[name][:] = src.variables[name][:]
    

    【讨论】:

    • 谢谢。我应该检查文件类型。我可能不会在这个工作流程中使用它,但我一定会记住这一点。现在唯一的怪癖是原始文件中的数据类型是 GeoTraj 或 Geo2D,在转换过程中它会将数据类型更改为 2D 和 1D。
    【解决方案3】:

    以下工作流程是否足够:

    ds = xr.open_dataset(fName)
    ds[toinclude].to_netcdf(file2)
    

    由于您提到尝试减小文件大小,您应该查看 Xarray 在"writing encoded data" 上的文档。您可能想要执行以下操作:

    encoding = {v: {'zlib: True, 'complevel': 4} for v in toinclude}
    ds[toinclude].to_netcdf(file2, encoding=encoding, engine='netcdf4')
    

    【讨论】:

    • 谢谢!就是这个!它实际上保留了原始文件中的变量和数据类型,并减少了文件大小。附带说明一下,使用 complevel 将大小减少了 0.2 MB。但是,有趣的是,即使将 complevel 更改为 9,文件大小仍保持 1.3 MB。
    猜你喜欢
    • 2019-12-02
    • 2018-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-02
    • 1970-01-01
    • 2016-12-27
    • 1970-01-01
    相关资源
    最近更新 更多