第一篇 NC數據深度優先檢索(Python)

第一篇 NC數據深度優先檢索

NetCDF是UCAR開發的一種通用數據格式,可能做環境或者地學的人會比較熟悉。這種數據格式非常方便使用者讀取和編輯,很多語言都可以對這種格式進行讀寫。這種格式會保留原有數據的長度、維度等信息,就像Python的.npy,matlab的.m和IDL的.sav文件一樣。NetCDF以.nc格式對數據進行存儲,所存儲的數據結構可以用一個數表示[1]:

Stephen R Clark,https://www.researchgate.net/figure/The-hierarchical-group-structure-for-an-example-output-file-in-NetCDF-format-The-groups_fig4_308964752
樹的根節點表示我們訪問的nc文件,每一個子節點表示一個group,一個nc文件可能會包含很多group,而每一個group下面也可能包含很多新的group。這一個棵樹的葉子就代表了該文件所儲存的數據集,根節點和子節點都可以鏈接到很多數據集。所以,nc文件下存儲的數據結構可能會很複雜,當我們知道所需數據的key(通常就是數據名稱)的時候,便可以通過深度優先檢索的方式對數據進行查找。

代碼實現

Anaconda目前並沒有自帶netCDF4的庫,所以首先我們需要自行安裝這個庫。和其他大部分庫的安裝一樣,打開命令行窗口,鍵入:

pip install netCDF4

pip就會自動幫助你安裝好netCDF4。

我一般會使用Spyder或者vim對腳本進行編輯,我們需要先導入所需要的庫:

import netCDF4 as nc
from numpy import *

然後我們定義一個類,簡單地來說這個類的核心就是一個棧,用來暫存我們在檢索過程中遇到的節點,包括根節點和子節點。當我們對某一個節點檢索,沒有發現我們所要找的數據時,就從這個棧的棧尾取出一個節點繼續檢索。這個地方不明白的話可以先了解一下深度優先檢索

class deep_search_nc:
    def __init__(self,nc_ob): #初始化,把根節點放入棧內
        self.ob_list_i = [nc_ob]
        self.ob_list = [nc_ob]
        
    def seek_for(self,varname):#單個數據集檢索
        if self.ob_list == []:#檢查是否空棧
            print('Cant find',varname)
            self.ob_list=self.ob_list_i.copy()
            return 1
        ob_temp = self.ob_list.pop()#從棧尾取出一個節點(並從棧尾刪除)
        if ob_temp.get_variables_by_attributes(name = varname) != []:
        #判斷節點內是否有目標數據集,有的話返回數據集
            self.ob_list=self.ob_list_i.copy()
            temp = ob_temp.variables[varname][:]
            if type(temp) == ma.core.MaskedArray:
                return temp.data.squeeze()
            elif type(temp) == ndarray:
                return temp.squeeze()
            else:
                print('unrecognized type',type(temp))
                return temp
        else:
        #沒有找到目標數據集,遞歸調用繼續檢索
            for key in list(ob_temp.groups.keys()):
                self.ob_list.append(ob_temp.groups[key])
            return self.seek_for(varname)
        
    def seek_lot_for(self,varnames):#多個數據集檢索
        if type(varnames) == str:
            varnames = [varnames]
        elif type(varnames) != list:
            print('wrong type of varnames!',varnames)
            return []
        return [self.seek_for(var) for var in varnames]

這個地方對函數進行了遞歸調用,這種方式可以使得代碼的編寫更加簡潔。
下面舉個例子,怎麼使用這個檢索工具。首先我們用nc.Dataset函數需要打開一個.nc文件,然後用它對我們的deep_search_nc類對象進行初始化,然後調用其中的seek_lot_for檢索函數:

NC_file_ob = deep_search_nc(nc.Dataset(NC_file,'r'))#NC_file是目標文件路徑,是一個字符串
nc_list= ['cloud_fraction_crb','cloud_pressure_crb','surface_pressure','surface_albedo','surface_albedo_nitrogendioxide_window','latitude_bounds','longitude_bounds','cloud_radiance_fraction_nitrogendioxide_window']
NC_file_ob.seek_lot_for(nc_list)#nc_list內包含了所有我們所想查找的數據集的key,通常來說就是變量名

參考資料

[1] https://www.researchgate.net/figure/The-hierarchical-group-structure-for-an-example-output-file-in-NetCDF-format-The-groups_fig4_308964752

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章