Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/360.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么netCDF4文件大小与写入方式如此不同?_Python_Netcdf_Filesize - Fatal编程技术网

Python 为什么netCDF4文件大小与写入方式如此不同?

Python 为什么netCDF4文件大小与写入方式如此不同?,python,netcdf,filesize,Python,Netcdf,Filesize,我有几个文本文件存储不同时间和不同组的二维数据(相同形状)。现在,我想将这些数据转换为一个包含多个netCDF组的netCDF文件。每个组的变量都有相同的维度,比如:维度:{time=62,lat=118,lon=104}。我用三种方式写数据。代码是用python3.7和netCDF4包编写的 from netCDF4 import Dataset, date2num, date2index import numpy as np import os from datetime import da

我有几个文本文件存储不同时间和不同组的二维数据(相同形状)。现在,我想将这些数据转换为一个包含多个netCDF组的netCDF文件。每个组的变量都有相同的维度,比如:
维度:{time=62,lat=118,lon=104}
。我用三种方式写数据。代码是用python3.7和netCDF4包编写的

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)
除文件大小外,这三种方法编写的文件都是相同的(变量的chunksize=(62U、118U、104U))

方式1:495324392字节(磁盘的503.3MB)

方式2:15680108字节(磁盘的16.7MB)

方式3:15680108字节(磁盘的16.7MB)

我想知道是否有人能为我解释一下。
谢谢!

这不是一个完整的答案,但我现在必须睡觉了,我想分享我到目前为止的发现。
h5ls
输出确实表明所有数据集的大小和块都相同,所以这不是问题所在

在您的程序中,您测试netCDF文件或变量是否存在,然后仅在它不存在时创建它。但是,您不测试组,而是始终创建它们。通过将
grp=rootgrp.createGroup(grppath)
更改为以下行,
way1.nc
的大小减小到19 MB

if grppath in rootgrp.groups:
    grp = rootgrp[grppath]
else:
    grp = rootgrp.createGroup(grppath)
从HDF5文件中删除对象时,文件大小保持不变(请参阅第5.5.2节:从文件中删除数据集并回收数据集的空间)。因此,我怀疑反复创建同名组会分配存储空间,但不会释放旧组的磁盘空间,从而造成内存泄漏。我不知道为什么这种情况只会以方式1发生,而不会以方式3发生

我也不明白为什么way1.nc仍然比其他的(15MB)稍大一些(19MB)


最后,因为只有在netCDF文件不存在的情况下才调用
initialize
函数,所以在启动程序之前必须小心删除上一次运行的输出。您很容易忘记这一点,因此我建议您修改代码,以便在程序启动时始终执行
initialize

您是谁是否实际阵列和数据块大小相同?您可以使用
h5ls
命令行工具(包括在HDF-5安装中)获取有关存储和卡盘的更多信息(因为NetCDF-4文件也是HDF-5文件)。也许这些信息也可以在HDF查看器中找到。但是我会在两个文件上使用
h5ls-r-v yourfile.nc
,然后使用diff查看器来比较和查找差异。您好,@titusjan。谢谢您的帮助。我已经按照您的说明打印了
h5ls
命令的结果。有很多不同的它们之间存在差异,但我不知道这意味着什么。我的代码创建的两个NC文件都是相同的,这意味着导出到NC文件的数据都是我想要的,只是文件大小不一样。我想了解为什么这些会有这么大的差异。对于每个数据集,都有一行
Chunks
显示实际块大小s、 这些都是预期的吗?
存储
行的问题相同。如果不是,您必须进行一些调试。以一个数据集为例,详细了解它是如何创建的。如果您需要我们的进一步帮助,您必须使用人工数据制作一个测试程序,以便我们可以重现该问题。制作一个。您提供的代码段不是c完成。也就是说,我无法运行它们并重现您的问题。@titusjan您能给我这些建议真是太好了。我已经编辑了问题,给出了完整的代码片段,使用了一些硬编码,并添加了第三种写入数据的方法。我认为代码片段现在可以在安装了所需软件包的计算机上运行。我是sti我不明白为什么way1和way2中的文件大小不同,但是way2和way3中的文件大小相同。我对创建正确的MRE表示赞赏和支持。请参阅我对目前为止发现的问题的回答。将
initialize
函数移到程序启动位置是一个很好的建议。但问题仍然没有解决。是否是否有必要在创建前测试组的存在性不是关键,请参阅。即使我在创建前测试组的存在性,
way1.nc
的大小在我的计算机(macOS 10.13.6)中仍然约为490MB。也许我需要阅读您提供的链接以找到答案。仍然感谢!