簡體   English   中英

為什么 netCDF4 文件大小與寫入方式如此不同?

[英]Why the netCDF4 file size are so different from the write ways?

我有幾個文本文件存儲具有不同時間和不同組的二維數據(相同形狀)。 現在我想將這些數據轉換為一個包含多個 netCDF 組的 netCDF 文件。 每個組的變量具有相同的維度,例如: dimensions:{time=62, lat=118, lon=104} 我以三種方式寫入數據。 代碼用python3.7和netCDF4 package編寫。

from netCDF4 import Dataset, date2num, date2index
import numpy as np
import os
from datetime import datetime, timedelta


def initialize(fpath):
    rootgrp = Dataset(fpath, 'w')
    rootgrp.createDimension('time', 62)
    rootgrp.createDimension('lat', 118)
    rootgrp.createDimension('lon', 104)

    times = rootgrp.createVariable('time', 'f8', ('time', ))
    lats = rootgrp.createVariable('lat', 'f4', ('lat', ))
    lons = rootgrp.createVariable('lon', 'f4', ('lon', ))

    lats.units = 'degrees north'
    lons.units = 'degrees east'
    times.units = 'hours since 1900-01-01 00:00:00.0'
    times.calendar = 'gregorian'
    datetimes = [
        datetime(2020, 3, 1, 8) + n * timedelta(hours=12) for n in range(62)
    ]

    lats[:] = np.linspace(-40, 40, 118)
    lons[:] = np.linspace(80, 160, 104)
    times[:] = date2num(datetimes, times.units, times.calendar)
    return rootgrp


def write(fpath, data, **kwargs):
    if not os.path.exists(fpath):
        rootgrp = initialize(fpath)
    else:
        rootgrp = Dataset(fpath, 'r+')

    grppath = kwargs['grppath']
    varname = kwargs['varname']
    grp = rootgrp.createGroup(grppath)
    if varname in grp.variables:
        var = grp.variables[varname]
    else:
        var = grp.createVariable(varname,
                                 'f4', ('time', 'lat', 'lon'),
                                 zlib=True,
                                 least_significant_digit=1)

    times = rootgrp.variables['time']
    datetimes = kwargs.get('datetimes', None)
    if datetimes is None:
        time_index = slice(None)
    else:
        time_index = date2index(datetimes, times, calendar=times.calendar)

    print(var[time_index, :, :].shape)
    print(data.shape)
    var[time_index, :, :] = data
    rootgrp.close()


def get_data(groups, datetimes):
    shape = (118, 104)
    size = shape[0] * shape[1]
    all_group = {}
    for group in groups:
        data_list = []
        for time in datetimes:
            data = np.random.random(size).reshape(shape)
            data_list.append(data)
        all_group[group] = data_list
    return all_group


def way1(dateimes, grouped_data):
    for i, time in enumerate(datetimes):
        for group, data in grouped_data.items():
            write('way1.nc',
                  data[i],
                  grppath=group,
                  varname='random',
                  datetimes=time)


def way2(datetimes, grouped_data):
    for group in grouped_data:
        all_data = np.stack(grouped_data[group])
        write('way2.nc',
              all_data,
              grppath=group,
              varname='random',
              datetimes=datetimes)


def way3(datetimes, grouped_data):
    for group, data in grouped_data.items():
        for i, time in enumerate(datetimes):
            write('way3.nc',
                  data[i],
                  grppath=group,
                  varname='random',
                  datetimes=time)


groups = list('abcdefghijklmnopqrstuvwxyz')
datetimes = [
    datetime(2020, 3, 1, 8) + n * timedelta(hours=12) for n in range(62)
]
grouped_data = get_data(groups, datetimes)
way1(datetimes, grouped_data)
way2(datetimes, grouped_data)
way3(datetimes, grouped_data)

三種方式寫入的文件都是一樣的(變量的ChunkSizes = (62U, 118U, 104U)),只是文件大小不同。

方式一:495,324,392 Bytes(磁盤503.3 MB)

方式2:15,608,108 Bytes(磁盤16.7 MB)

方式3:15,608,108 Bytes(磁盤16.7 MB)

我想知道是否有人可以為我解釋。 謝謝!

不是一個完整的答案,但我現在必須 go 睡覺,並想分享我到目前為止發現的內容。 h5ls output 確實表明所有數據集的大小和塊都相同,所以這不是問題。

在您的程序中,您測試 netCDF 文件或變量是否存在,然后僅在尚不存在時創建它。 但是,您不測試組,您總是創建它們。 通過將grp = rootgrp.createGroup(grppath)更改為以下行, way1.nc的大小減少到 19 MB。

if grppath in rootgrp.groups:
    grp = rootgrp[grppath]
else:
    grp = rootgrp.createGroup(grppath)

從 HDF5 文件中刪除 object 時,文件大小保持不變(請參閱HDF5 用戶指南的第 5.5.2 節。從文件中刪除數據集和回收空間)。 所以我懷疑一遍又一遍地創建一個同名的組會分配存儲空間但不會釋放舊組的磁盤空間,從而造成 memory 泄漏。 我不知道為什么這種情況只發生在方式 1 中,而不發生在方式 3 中。

另外我還不明白為什么way1.nc仍然比其他文件(15 MB)略大(19 MB)。

最后,因為只有在netCDF文件不存在的情況下才調用initialize function,所以在啟動程序之前一定要小心刪除之前運行的output。 您很容易忘記這一點,因此我建議您修改代碼,以便始終在程序啟動時執行initialize

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM