利用python如何處理nc數(shù)據(jù)詳解
前言
這兩天幫一個朋友處理了些 nc 數(shù)據(jù),本以為很簡單的事情,沒想到里面涉及到了很多的細節(jié)和坑,無論是“知難行易”還是“知易行難”都不能充分的說明問題,還是“知行合一”來的更靠譜些,既要知道理論又要知道如何實現(xiàn),于是經(jīng)過不太充分的研究后總結(jié)成此文,以記錄如何使用 python 處理 nc 數(shù)據(jù)。
一、nc 數(shù)據(jù)介紹
nc 全稱 netCDF(The Network Common Data Form),可以用來存儲一系列的數(shù)組,就是這么簡單(參考https://www.unidata.ucar.edu/software/netcdf/docs/netcdf_introduction.html)。
既然 nc 可以用來一系列的數(shù)組,所以經(jīng)常被用來存儲科學觀測數(shù)據(jù),最好還是長時間序列的。
試想一下一個科學家每隔一分鐘采集一次實驗數(shù)據(jù)并存儲了下來,如果不用這種格式存儲,時間長了可能就需要創(chuàng)建一系列的 csv 或者 txt 等,而采用 nc 一個文件就可以搞定,是不是很方便。
更方便的是如果這個科學實驗與氣象、水文、溫度等地理信息稍微沾點邊的,完全也可以用 nc 進行存儲, GeoTiff 頂多能多存幾個波段(此處波段可以認為是氣象、水文等不同信號),而 nc 可以存儲不同波段的長時間觀測結(jié)果,是不是非常方便。
可以使用 gdal 查看數(shù)據(jù)信息,執(zhí)行:
gdalinfo name.nc
即可得到如下信息:
Driver: netCDF/Network Common Data Format Files: test.nc Size is 512, 512 Coordinate System is `' Subdatasets: SUBDATASET_1_NAME=NETCDF:"test.nc":T2 SUBDATASET_1_DESC=[696x130x120] T2 (32-bit floating-point) SUBDATASET_2_NAME=NETCDF:"test.nc":PSFC SUBDATASET_2_DESC=[696x130x120] PSFC (32-bit floating-point) SUBDATASET_3_NAME=NETCDF:"test.nc":Q2 SUBDATASET_3_DESC=[696x130x120] Q2 (32-bit floating-point) SUBDATASET_4_NAME=NETCDF:"test.nc":U10 SUBDATASET_4_DESC=[696x130x120] U10 (32-bit floating-point) SUBDATASET_5_NAME=NETCDF:"test.nc":V10 SUBDATASET_5_DESC=[696x130x120] V10 (32-bit floating-point) SUBDATASET_6_NAME=NETCDF:"test.nc":RAINC SUBDATASET_6_DESC=[696x130x120] RAINC (32-bit floating-point) SUBDATASET_7_NAME=NETCDF:"test.nc":SWDOWN SUBDATASET_7_DESC=[696x130x120] SWDOWN (32-bit floating-point) SUBDATASET_8_NAME=NETCDF:"test.nc":GLW SUBDATASET_8_DESC=[696x130x120] GLW (32-bit floating-point) SUBDATASET_9_NAME=NETCDF:"test.nc":LAT SUBDATASET_9_DESC=[130x120] LAT (32-bit floating-point) SUBDATASET_10_NAME=NETCDF:"test.nc":LONG SUBDATASET_10_DESC=[130x120] LONG (32-bit floating-point) Corner Coordinates: Upper Left ( 0.0, 0.0) Lower Left ( 0.0, 512.0) Upper Right ( 512.0, 0.0) Lower Right ( 512.0, 512.0) Center ( 256.0, 256.0)
每一個 SUBDATASET 表示記錄的是一種格式的數(shù)據(jù)(氣象、水文等等),如果要想查看此 SUBDATASET 的具體信息,可以執(zhí)行:
gdalinfo NETCDF:name.nc:SUBDATASET_NAME
此處的 SUBDATASET_NAME 為上面的 T2、PSFC 等等,可以得到如下信息:
Driver: netCDF/Network Common Data Format Files: test.nc Size is 120, 130 Coordinate System is `' Metadata: LAT#description=LATITUDE, SOUTH IS NEGATIVE LAT#FieldType=104 LAT#MemoryOrder=XY LAT#stagger= LAT#units=degree_north Corner Coordinates: Upper Left ( 0.0, 0.0) Lower Left ( 0.0, 130.0) Upper Right ( 120.0, 0.0) Lower Right ( 120.0, 130.0) Center ( 60.0, 65.0) Band 1 Block=120x1 Type=Float32, ColorInterp=Undefined NoData Value=9.96920996838686905e+36 Unit Type: degree_north Metadata: description=LATITUDE, SOUTH IS NEGATIVE FieldType=104 MemoryOrder=XY NETCDF_VARNAME=LAT stagger= units=degree_north
此處只有一個 Band ,每一個 Band 記錄了一個時間點(或者其他區(qū)分形式)的一條記錄,這個記錄是一個數(shù)組。
所以看到這里,各位應(yīng)該已經(jīng)明白了,可以直接使用 GDAL 處理 nc 數(shù)據(jù),比如直接使用 gdalwarp 將某個 SUBDATASET 轉(zhuǎn)成 GeoTiff 等等,此處暫且不表,各位只需要查閱一下 gdalwarp 手冊即可知道如何處理。
明白了以上信息基本也就清楚了如何處理此數(shù)據(jù)。
二、數(shù)據(jù)處理
python 是運用非常廣泛,自然其下各種類庫非常豐富,專業(yè)一點的說法就叫生態(tài)豐富。
2.1 netCDF4
此框架可以直接將 nc 讀取成數(shù)組(詳細信息參考https://github.com/Unidata/netcdf4-python (本地下載))。讀取方式如下:
dataset = netCDF4.Dataset('name.nc') # open the dataset
這樣即可讀出整個 nc 中的數(shù)據(jù)信息,如果需要獲取某個 SUBDATASET 只需要使用 dataset[SUBDATASET_NAME] 即可,返回的是一個三維數(shù)組,表示不同時間段(或其他區(qū)分方式下)的數(shù)據(jù)信息。
我們可以對此數(shù)組做各種操作,如求平均值、方差等等,又讓我想起了大學里的那一堆枯燥但又讓人很有興趣的實驗課程。當然,此處如果使用 numpy 框架進行處理,會起到事半功倍的效果,如求長時間序列下的平均值:
np_arr = np.asarray(dataset[SUBDATASET_NAME]) average_arr = np.average(np_arr, axis=0)
到這里跟地信有關(guān)的同志都會看出一個問題,此框架只能對數(shù)據(jù)進行處理,而不能進行與位置有關(guān)的操作,這就導致數(shù)據(jù)無法變成直白的地圖可視化效果。其實任何數(shù)據(jù)都是相通的,我們可以采用此種方式處理完后轉(zhuǎn)為 GeoTiff 等,當然我們也可以直接采用 GeoTiff 的處理流程來進行處理。
2.2 rasterio
rasterio 是 Mapbox 開源的空間數(shù)據(jù)處理框架,功能非常強大,此處不細說,只表如何處理我們的 nc 數(shù)據(jù)。
當然第一種方式就是使用 netCDF4 處理完之后,使用此框架寫入 GeoTiff,但是這樣不太優(yōu)雅,而且使用了兩個框架,明顯過于麻煩,我們直接使用此框架從讀數(shù)據(jù)開始處理。
此處讀的時候就有技巧了,要像采用 gdalinfo 讀取 SUBDATASET 一樣來直接讀取此 SUBDATASET 數(shù)據(jù),如下:
with rio.open('NETCDF:name.nc:SUBDATASET_NAME') as src:
print(src.meta)
dim = int(src.meta['count'])
src.read(range(1, dim + 1))
即給 open 函數(shù)傳入 NETCDF:name.nc:SUBDATASET_NAME,采用 src.read(range(1, dim + 1)) 可以直接讀出此范圍內(nèi)所有 Band (時間點)的信息,范圍可以自己設(shè)定,注意從 0 開始,當然也可以僅讀取某個 Band 的信息。
src.meta 記錄了此 SUBDATASET 的元數(shù)據(jù)信息,與 gdalinfo 看到的基本相同。
這樣我們就可以繼續(xù)將此數(shù)據(jù)使用 numpy 等框架進行處理,處理完之后更重要的是要寫入 GeoTiff 中(直白的說就是添加空間信息)。
也很簡單,如下即可:
with rio.open(newfile, 'w', **out_meta) as dst: dst.write_band(1, res_arr)
newfile 為存儲路徑,res_arr 為計算結(jié)果數(shù)組,注意尺寸不要發(fā)生變化(width*height),out_meta 為目標文件的元數(shù)據(jù)描述信息,可以直接將上面 src.meta 進行簡單處理即可。
out_meta =
meta.update({"driver": "GTiff",
"dtype": "float32",
'count': 1,
'crs': 'Proj4: +proj=longlat +datum=WGS84 +no_defs',
'transform': rasterio.transform.from_bounds(west, south, east, north, width, height)
})
crs 表示目標數(shù)據(jù)空間投影信息,transform 表示目標文件 空間范圍信息,可以通過經(jīng)緯度信息和圖像尺寸等計算得到。
dst.write_band 將數(shù)據(jù)寫入對應(yīng)波段,當然此處也可以寫入多個波段,根據(jù)計算結(jié)果而定,同樣從 1 開始。
三、總結(jié)
本文簡單介紹了 nc 數(shù)據(jù)的特點及如何使用 python 處理 nc 數(shù)據(jù)。每個目標都有多條路可以達到,重要的是找到那條自己喜歡的和適合自己的路,然而話又說回來,即使走的不是想要的那條路,不是一樣可以達到目標嘛!所以關(guān)鍵是要找到自己的目標。
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
使用WingPro 7 設(shè)置Python路徑的方法
Python使用稱為Python Path的搜索路徑來查找使用import語句導入代碼的模塊。這篇文章主要介紹了使用WingPro 7 設(shè)置Python路徑的方法,需要的朋友可以參考下2019-07-07
Jupyter Notebook內(nèi)使用argparse報錯的解決方案
這篇文章主要介紹了在Jupyter Notebook內(nèi)使用argparse報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06
python:批量統(tǒng)計xml中各類目標的數(shù)量案例
這篇文章主要介紹了python:批量統(tǒng)計xml中各類目標的數(shù)量案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
詳解Python中四種關(guān)系圖數(shù)據(jù)可視化的效果對比
python關(guān)系圖的可視化主要就是用來分析一堆數(shù)據(jù)中,每一條數(shù)據(jù)的節(jié)點之間的連接關(guān)系從而更好的分析出人物或其他場景中存在的關(guān)聯(lián)關(guān)系。本文將制作四個不同的關(guān)系圖的可視化效果,感興趣的可以了解一下2022-11-11

