【Python】netCDF4 packed学习

本文探讨了如何使用netCDF4库在创建nc文件时利用scale_factor和add_offset进行数据压缩,展示了读写操作中数据的自动打包和解包过程。通过实例代码和比较,理解了压缩对精度的影响并提供相关参考链接。

目录

说明

代码实现

运行结果

 参考


说明

        本文为博主原创文章,未经博主允许不得转载。

        用netCDF4库来写nc文件的时候,如果maskandscale设置为True(默认为True),且数据变量包含scale_factor或者add_offset,读写数据时候自动进行打包和解包。

1)读取数据时候,自动解包:

data = self.scale_factor*data + self.add_offset

2)写入数据时自动打包:

data = (data - self.add_offset )/self.scale_factor

        通过下面代码可以更加清楚理解这一概念。

代码实现

test_nc_write.py

# --*-- coding:utf-8 --*--

import xarray as xr
import netCDF4
import numpy as np

def calculate_scale_and_offset(minimum, maximum, n):
    scale = (maximum - minimum) / (2 ** n - 1)
    offset = minimum + 2 ** (n - 1) * scale
    return scale, offset


# 不压缩数据
def write_nc_1(filename,data,format='NETCDF4'):
    dset = netCDF4.Dataset(filename, mode='w', format=format)
    # create dimensions
    dset.createDimension('z', data.shape[0])
    dset.createDimension('y', data.shape[1])
    dset.createDimension('x', data.shape[2])

    dtype = data.dtype

    # use scale_factor and add_offset to pack data.
    minimum = np.min(data)
    maximum = np.max(data)
    # dtype = 'i4'
    # scale, offset = calculate_scale_and_offset(minimum,maximum, 16)

    # create the dataset variable
    kwargs = {'zlib': True}
    ncvar = dset.createVariable('v', dtype, ('z','y','x'), **kwargs)

    # ncvar.setncattr('scale_factor',scale)
    # ncvar.setncattr('add_offset',offset)

    ncvar[:] = data[:]

    dset.close()

# 采用set_auto_maskandscale自动压缩
def write_nc_2(filename,data,format='NETCDF4'):
    dset = netCDF4.Dataset(filename, mode='w', format=format)
    # create dimensions
    dset.createDimension('z', data.shape[0])
    dset.createDimension('y', data.shape[1])
    dset.createDimension('x', data.shape[2])
    
    # use scale_factor and add_offset to pack data.
    minimum = np.min(data)
    maximum = np.max(data)
    dtype = 'i4'
    scale, offset = calculate_scale_and_offset(minimum,maximum, 16)

    # create the dataset variable
    kwargs = {'zlib': True}
    ncvar = dset.createVariable('v', dtype, ('z','y','x'), **kwargs)

    ncvar.setncattr('scale_factor',scale)
    ncvar.setncattr('add_offset',offset)

    ncvar[:] = data[:]

    dset.close()


# 自己压缩(即不使用系统保留的scale_factor和add_offset)
def write_nc_3(filename,data,format='NETCDF4'):
    dset = netCDF4.Dataset(filename, mode='w', format=format)
    # create dimensions
    dset.createDimension('z', data.shape[0])
    dset.createDimension('y', data.shape[1])
    dset.createDimension('x', data.shape[2])
    
    # use scale_factor and add_offset to pack data.
    minimum = np.min(data)
    maximum = np.max(data)
    dtype = 'i4'
    scale, offset = calculate_scale_and_offset(minimum,maximum, 16)

    # create the dataset variable
    kwargs = {'zlib': True}
    ncvar = dset.createVariable('v', dtype, ('z','y','x'), **kwargs)

    ncvar.setncattr('v_scale',scale)
    ncvar.setncattr('v_offset',offset)

    # 自己对数据进行压缩
    data = np.floor((data - offset) / scale)

    ncvar[:] = data[:]

    dset.close()

if __name__ == '__main__':
    # create data to write
    nx,ny,nz = 500,500,10
    np.random.seed(1234)
    data = np.random.rand(nz,ny,nx)
    print('\n','orignal=',data[:,0,0])

    file_1 = 'test_1.nc'
    write_nc_1(file_1,data)

    file_2 = 'test_2.nc'
    write_nc_2(file_2,data)

    file_3 = 'test_3.nc'
    write_nc_3(file_3,data)

    ds1 = xr.open_dataset(file_1)
    print('\n','ds1=',ds1)
    print('\n','ds1=',ds1.v.values[:,0,0])

    # 默认set_auto_maskandscale=True,属性中包含scale_factor or add_offset时,
    # 写入的时候,自动打包;读取的时候,自动解包,即内部完成了write_nc_3的操作
    ds2 = xr.open_dataset(file_2)
    print('\n','ds2=',ds2)
    print('\n','ds2=',ds2.v.values[:,0,0])

    # 使用的时候对数据解包
    ds3 = xr.open_dataset(file_3)
    offset = ds3['v'].attrs['v_offset']
    scale = ds3['v'].attrs['v_scale']
    print('\n','ds3=',ds3)
    print('\n','ds3=',ds3.v.values[:,0,0]*scale + offset)

运行结果

        采用scale_factor 和 add_offset 对浮点型数据进行压缩,能有效减少所需要的存储空间,但同时也会损失一些数据精度(如上图所示) 。

参考

1、官方文档 netCDF4 API documentation

我下载了NSIDC的南极数据,网格为322*316,我现在有记录了每个网格的面积的hdf数据,请根据hdf数据给我计算出nc文件中变量的实际面积。我的NSIDC文件的命名为G:\NSIDC0081_SEAICE_PS_S25km_20250924_v2.0.nc,nc文件读取的是F16_ICECON,hdf文件命名为G:\pss25area_v3.hdf,关于网格面积的参数为data,单位是平方千米。读取hdf文件的代码参考下面这个 ’‘’ from netCDF4 import Dataset # 指定文件路径 file_path = r'D:\dataset\grid\lon_lat_316_332.hdf' # 打开HDF4文件 hdf_file = Dataset(file_path, 'r') ‘’‘ 一共有322行,316列,网格位置的实际面积对应这hdf的行列数据。我要的海冰实际面积应该是海冰实际面积占网格面积的百分比*网格的实际面积。我的数据是南极数据,F16_ICECON变量的相关内容为:他的范围为0-1 变量名称: F16_ICECON 变量形状: (1, 332, 316) 变量数据类型: uint8 变量维度: ('time', 'y', 'x') 变量属性: _FillValue: 255 legacy_binary_header: [ 48 48 50 53 53 0 32 32 51 49 54 0 32 32 51 51 50 0 49 46 55 57 57 0 45 53 49 46 51 0 50 55 48 46 48 0 53 53 56 46 52 0 49 53 56 46 48 0 49 55 52 46 48 0 83 83 77 73 83 0 49 54 32 99 110 0 32 32 50 54 55 0 45 57 57 57 57 0 45 57 57 57 57 0 32 32 50 54 55 0 45 57 57 57 57 0 45 57 57 57 57 0 32 50 48 50 53 0 32 32 50 54 55 0 32 32 48 48 48 0 48 48 50 53 48 0 32 32 110 116 95 50 48 50 53 48 57 50 52 95 102 49 54 95 110 114 116 95 115 0 65 78 84 65 82 67 84 73 67 32 83 83 77 73 83 32 32 84 79 84 65 76 32 73 67 69 32 67 79 78 67 69 78 84 82 65 84 73 79 78 32 32 32 32 32 32 32 68 77 83 80 32 32 70 49 54 32 32 32 32 32 68 65 89 32 50 54 55 32 48 57 47 50 52 47 50 48 50 53 0 65 78 84 65 82 67 84 73 67 32 32 83 83 77 73 83 79 78 83 83 77 73 71 82 73 68 32 67 79 78 32 67 111 97 115 116 50 53 51 80 111 108 101 50 53 49 76 97 110 100 50 53 52 32 32 32 32 32 32 48 57 47 50 55 47 50 48 50 53 0] units: Fraction between 0.0 - 1.0 long_name: Sea Ice Concentration standard_name: sea_ice_area_fraction grid_mapping: crs coverage_content_type: image valid_range: [ 0 250] coordinates: time y x flag_values: [251 252 253 254] flag_meanings: pole_hole_mask unused coast land packing_convention: netCDF packing_convention_description: unpacked = scale_factor*packed + add_offset scale_factor: 0.004 add_offset: 0.0 comment: The legacy_binary_header is a 300-byte string that has historically been prepended to the raw binary data in version 1 of data product. It is provided for those interested in backward compatibility of the NetCDF data file with the version 1 binary data files. 变量数据: [[[0.0 0.0 0.0 ... 0.0 0.0 0.0] [0.0 0.0 0.0 ... 0.0 0.0 0.0] [0.0 0.0 0.0 ... 0.0 0.0 0.0] ... [0.0 0.0 0.0 ... 0.0 0.0 0.0] [0.0 0.0 0.0 ... 0.0 0.0 0.0] [0.0 0.0 0.0 ... 0.0 0.0 0.0]]] 应该是海冰浓度乘网格面积进行相加即可对吧? nc和hdf文件用from netCDF4 import Dataset读取即可
11-13
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值