【算法竞赛学习】气象海洋预测-Task1 气象数据分析常用工具
氣象海洋預測-Task1 氣象數據分析常用工具
氣象科學中的數據通常包含多個維度,例如本賽題中給出的數據就包含年、月、經度、緯度四個維度,為了便于數據的讀取和操作,氣象數據通常采用netCDF文件來存儲,文件后綴為.nc。
對于以netCDF文件存儲的氣象數據,有兩個常用的數據分析庫,即NetCDF4和Xarray。在此次任務中,我們將學習這兩個庫的基本對象和基本操作,掌握用這兩個庫讀取和處理氣象數據的基本方法。
學習目標
1.了解和學習NetCDF4和Xarray的基本對象和基本操作,掌握用這兩個庫讀取和處理氣象數據的基本方法。
內容介紹
- 創建、打開和關閉netCDF文件
- 組(Groups)
- 維度(Dimensions)
- 變量(Variables)
- 屬性(Attributes)
- 寫入或讀取變量數據
- 應用
- 創建DataArray
- 索引
- 屬性
- 計算
- GroupBy
- 繪圖
- 與Pandas對象相互轉換
- Dataset
- 讀/寫netCDF文件
- 應用
NetCDF4
官方文檔
NetCDF4是NetCDF C庫的Python模塊,支持Groups、Dimensions、Variables和Attributes等對象類型及其相關操作。
安裝NetCDF4
!pip install netCDF4 import netCDF4 as nc創建、打開和關閉netCDF文件
NetCDF4可以通過調用Dataset創建netCDF文件或打開已存在的文件,并通過查看data_model屬性確定文件的格式。需要注意創建或打開文件后要先關閉文件才能再次調用Dataset打開文件。
- 創建netCDF文件
- 打開已存在的netCDF文件
- 查看文件格式
- 關閉netCDF文件
Groups
NetCDF4支持按層級的組(Groups)來組織數據,類似于文件系統中的目錄,Groups中可以包含Variables、Dimenions、Attributes對象以及其他Groups對象,Dataset會創建一個特殊的Groups,稱為根組(Root Group),類似于根目錄,使用Dataset.createGroup方法創建的組都包含在根組中。
- 創建Groups
- 查看文件中的所有Groups
- Groups嵌套
- 遍歷查看所有Groups
Dimensions
NetCDF4用維度來定義各個變量的大小,例如本賽題中訓練樣本的第二維度month就是一個維度對象,每個樣本包含36個月的數據,因此month維度內的變量的大小就是36。變量是包含在維度中的,因此在創建每個變量時要先創建其所在的維度。
- 創建Dimensions
Dataset.createDimension方法接受兩個參數:維度名稱,維度大小。維度大小設置為None或0時表示無窮維度。
# 創建無窮維度 level = test.createDimension('level', None) time = test.createDimension('time', None) # 創建有限維度 lat = test.createDimension('lat', 180) lon = test.createDimension('lon', 360)- 查看Dimensions
- 查看維度大小
Variables
NetCDF4的Variables對象類似于Numpy中的多維數組,不同的是,NetCDF4的Variables變量可以存儲在無窮維度中。
- 創建Variables
Dataset.createVariable方法接受的參數為:變量名,變量的數據類型,變量所在的維度。
變量的有效數據類型包括:‘f4’(32位浮點數)、‘f8’(64位浮點數)、‘i1’(8位有符號整型)、‘i2’(16位有符號整型)、‘i4’(32位有符號整型)、‘i8’(64位有符號整型)、‘u1’(8位無符號整型)、‘u2’(16位無符號整型)、‘u4’(32位無符號整型)、‘u8’(64位無符號整型)、‘s1’(單個字符)。
# 創建單個維度上的變量 times = test.createVariable('time', 'f8', ('time',)) levels = test.createVariable('level', 'i4', ('level',)) lats = test.createVariable('lat', 'f4', ('lat',)) lons = test.createVariable('lon', 'f4', ('lon',))# 創建多個維度上的變量 temp = test.createVariable('temp', 'f4', ('time', 'level', 'lat', 'lon')) times <class 'netCDF4._netCDF4.Variable'> float64 time(time) unlimited dimensions: time current shape = (0,) filling on, default _FillValue of 9.969209968386869e+36 used levels <class 'netCDF4._netCDF4.Variable'> int32 level(level) unlimited dimensions: level current shape = (0,) filling on, default _FillValue of -2147483647 used- 查看Variables
Attributes
Attributes對象用于存儲對文件或維變量的描述信息,netcdf文件中包含兩種屬性:全局屬性和變量屬性。全局屬性提供Groups或整個文件對象的信息,變量屬性提供Variables對象的信息,屬性的名稱可以自己設置,下面例子中的description和history等都是自定義的屬性名稱。
import time# 設置對文件的描述 test.description = 'bogus example script' # 設置文件的歷史信息 test.history = 'Created' + time.ctime(time.time()) # 設置文件的來源信息 test.source = 'netCDF4 python module tutorial' # 設置變量屬性 lats.units = 'degrees north' lons.units = 'degrees east' levels.units = 'hPa' temp.units = 'K' times.units = 'hours since 0001-01-01 00:00:00.0' times.calendar = 'gregorian' # 查看文件屬性名稱 print(test.ncattrs()) # 查看變量屬性名稱 print(test['lat'].ncattrs()) print(test['time'].ncattrs()) ['description', 'history', 'source'] ['units'] ['units', 'calendar'] # 查看文件屬性 for name in test.ncattrs():print('Global attr {} = {}'.format(name, getattr(test, name))) Global attr description = bogus example script Global attr history = CreatedTue Jan 11 19:47:20 2022 Global attr source = netCDF4 python module tutorial寫入或讀取變量數據
類似于數組,可以通過切片的方式向變量中寫入或讀取數據。
- 向變量中寫入數據
- 讀取變量中的數據
應用
我們嘗試用NetCDF4來操作一下訓練樣本中的SODA數據。
# 打開SODA文件 soda = Dataset('test.nc') # 查看文件格式 print('SODA文件格式:', soda.data_model) # 查看文件中包含的對象 print(soda) SODA文件格式: NETCDF4 <class 'netCDF4._netCDF4.Dataset'> root group (NETCDF4 data model, file format HDF5):description: bogus example scripthistory: CreatedTue Jan 11 19:47:20 2022source: netCDF4 python module tutorialdimensions(sizes): level(10), time(5), lat(180), lon(360)variables(dimensions): float64 time(time), int32 level(level), float32 lat(lat), float32 lon(lon), float32 temp(time, level, lat, lon)groups: group1, group2 # 查看維度和變量 print(soda.dimensions) print(soda.variables) OrderedDict([('level', <class 'netCDF4._netCDF4.Dimension'> (unlimited): name = 'level', size = 10), ('time', <class 'netCDF4._netCDF4.Dimension'> (unlimited): name = 'time', size = 5), ('lat', <class 'netCDF4._netCDF4.Dimension'>: name = 'lat', size = 180), ('lon', <class 'netCDF4._netCDF4.Dimension'>: name = 'lon', size = 360)]) OrderedDict([('time', <class 'netCDF4._netCDF4.Variable'> float64 time(time)units: hours since 0001-01-01 00:00:00.0calendar: gregorian unlimited dimensions: time current shape = (5,) filling on, default _FillValue of 9.969209968386869e+36 used), ('level', <class 'netCDF4._netCDF4.Variable'> int32 level(level)units: hPa unlimited dimensions: level current shape = (10,) filling on, default _FillValue of -2147483647 used), ('lat', <class 'netCDF4._netCDF4.Variable'> float32 lat(lat)units: degrees north unlimited dimensions: current shape = (180,) filling on, default _FillValue of 9.969209968386869e+36 used), ('lon', <class 'netCDF4._netCDF4.Variable'> float32 lon(lon)units: degrees east unlimited dimensions: current shape = (360,) filling on, default _FillValue of 9.969209968386869e+36 used), ('temp', <class 'netCDF4._netCDF4.Variable'> float32 temp(time, level, lat, lon)units: K unlimited dimensions: time, level current shape = (5, 10, 180, 360) filling on, default _FillValue of 9.969209968386869e+36 used)])可以看到,SODA文件中包含year、month、lat、lon四個維度,維度大小分別是100、36、24和72,包含sst、t300、ua、va四個變量,每個變量都定義在(year, month, lat, lon)維度上。
# 讀取每個變量中的數據 soda_sst = soda['level'][:] print(soda_sst[1])soda_t300 = soda['temp'][:] print(soda_t300[1, 2, 12:24, 36])# soda_ua = soda['ua'][:] # print(soda_ua[1, 2, 12:24:2, 36:38])# soda_va = soda['va'][:] # print(soda_va[5:10, 0:12, 12, 36])# 關閉文件 soda.close() -- [0.31591734 0.59989274 0.44380635 0.7643542 0.5319885 0.788631860.97203755 0.4588462 0.19999161 0.9740341 0.65341175 0.9087504 ]Xarray
官方文檔
Xarray是一個開源的Python庫,支持在類似Numpy的多維數組上引入維度、坐標和屬性標記并可以直接使用標記的名稱進行相關操作,能夠讀寫netcdf文件并進行進一步的數據分析和可視化。
Xarray有兩個基本的數據結構:DataArray和Dataset,這兩個數據結構都是在多維數組上建立的,其中DataArray用于標記的實現,Dataset則是一個類似于字典的DataArray容器。
安裝Xarray要求滿足以下依賴包:
- Python(3.7+)
- setuptools(40.4+)
- Numpy(1.17+)
- Pandas(1.0+)
創建DataArray
xr.DataArray接受三個輸入參數:數組,維度,坐標。其中維度為數組的維度名稱,坐標以字典的形式給維度賦予坐標標簽。
# 創建一個2x3的數組,將維度命名為'x'和'y',并賦予'x'維度10和20兩個坐標標簽 data = xr.DataArray(np.random.randn(2, 3), dims=('x', 'y'), coords={'x': [10, 20]}) data # 查看數據 print(data.values)# 查看維度 print(data.dims)# 查看坐標 print(data.coords)# 可以用data.attrs字典來存儲任意元數據 print(data.attrs) [[-1.89477837 -0.58997363 -1.77758946][-0.21793173 0.77616912 0.45868184]] ('x', 'y') Coordinates:* x (x) int64 10 20 {}索引
Xarray支持四種索引方式。
# 通過位置索引,類似于numpy print(data[0, :], '\n')# 通過坐標標簽索引 print(data.loc[10], '\n')# 通過維度名稱和位置索引,isel表示"integer select" print(data.isel(x=0), '\n')# 通過維度名稱和坐標標簽索引,sel表示"select" print(data.sel(x=10), '\n') <xarray.DataArray (y: 3)> array([-1.89477837, -0.58997363, -1.77758946]) Coordinates:x int64 10 Dimensions without coordinates: y <xarray.DataArray (y: 3)> array([-1.89477837, -0.58997363, -1.77758946]) Coordinates:x int64 10 Dimensions without coordinates: y <xarray.DataArray (y: 3)> array([-1.89477837, -0.58997363, -1.77758946]) Coordinates:x int64 10 Dimensions without coordinates: y <xarray.DataArray (y: 3)> array([-1.89477837, -0.58997363, -1.77758946]) Coordinates:x int64 10 Dimensions without coordinates: y屬性
和NetCDF4一樣,Xarray也支持自定義DataArray或標記的屬性描述。
# 設置DataArray的屬性 data.attrs['long_name'] = 'random velocity' data.attrs['units'] = 'metres/sec' data.attrs['description'] ='A random variable created as an example' data.attrs['ramdom_attribute'] = 123 # 查看屬性 print(data.attrs) {'long_name': 'random velocity', 'units': 'metres/sec', 'description': 'A random variable created as an example', 'ramdom_attribute': 123} # 設置維度標記的屬性描述 data.x.attrs['units'] ='x units' print('Attributes of x dimension:', data.x.attrs, '\n') Attributes of x dimension: {'units': 'x units'}計算
DataArray的計算方式類似于numpy ndarray。
data + 10 data.T data.sum()可以直接使用維度名稱進行聚合操作。
data.mean(dim='x')DataArray之間的計算操作可以根據維度名稱進行廣播。
a = xr.DataArray(np.random.randn(3), [data.coords['y']]) b = xr.DataArray(np.random.randn(4), dims='z') print(a, '\n') print(b, '\n') print(a+b, '\n') <xarray.DataArray (y: 3)> array([0.04405523, 0.36823828, 0.38351121]) Coordinates:* y (y) int64 0 1 2 <xarray.DataArray (z: 4)> array([ 0.62771044, -0.41870179, -1.38038185, -0.19742089]) Dimensions without coordinates: z <xarray.DataArray (y: 3, z: 4)> array([[ 0.67176567, -0.37464656, -1.33632661, -0.15336566],[ 0.99594872, -0.05046351, -1.01214356, 0.17081739],[ 1.01122165, -0.03519058, -0.99687063, 0.18609032]]) Coordinates:* y (y) int64 0 1 2 Dimensions without coordinates: z data - data.T data[:-1] - data[:1]GroupBy
Xarray支持使用類似于Pandas的API進行分組操作。
labels = xr.DataArray(['E', 'F', 'E'], [data.coords['y']], name='labels') labels # 將data的y坐標對齊labels后按labels的值分組求均值 data.groupby(labels).mean('y') # 將data的y坐標按labels分組后減去組內的最小值 data.groupby(labels).map(lambda x: x - x.min())繪圖
Xarray支持簡單方便的可視化操作,這里只做簡單的介紹,更多的繪圖方法感興趣的同學們可以自行去探索。
%matplotlib inline data.plot() <matplotlib.collections.QuadMesh at 0x7f7ea4327828>[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mEPsd2AX-1645665921672)(Task1_files/Task1_116_1.png)]
與Pandas對象互相轉換
Xarray可以方便地轉換成Pandas的Series或DataFrame,也可以由Pandas對象轉換回Xarray。
# 轉換成Pandas的Series series = data.to_series() series x y 10 0 -1.8947781 -0.5899742 -1.777589 20 0 -0.2179321 0.7761692 0.458682 dtype: float64 # Series轉換成Xarray series.to_xarray() # 轉換成Pandas的DataFrame df = data.to_dataframe(name='colname') df| -1.894778 |
| -0.589974 |
| -1.777589 |
| -0.217932 |
| 0.776169 |
| 0.458682 |
Dataset
Dataset是一個類似于字典的DataArray的容器,可以看作是一個具有多為結構的DataFrame。對比NetCDF4庫中的Dataset,我們可以發現兩者的作用是相似的,都是作為容器用來存儲其他的對象。
# 創建一個Dataset,其中包含三個DataArray ds = xr.Dataset({'foo': data, 'bar': ('x', [1, 2]), 'baz': np.pi}) ds可以通過字典的方式或者點索引的方式來查看DataArray,但是只有采用字典方式時才可以進行賦值。
# 通過字典方式查看DataArray print(ds['foo'], '\n')# 通過點索引的方式查看DataArray print(ds.foo)讀/寫netCDF文件
# 寫入到netcdf文件 ds.to_netcdf('xarray_test.nc')# 讀取已存在的netcdf文件 xr.open_dataset('xarray_test.nc')應用
嘗試用Xarray來操作一下訓練樣本中的SODA數據。
# 打開SODA文件 soda = xr.open_dataset('SODA_train.nc') # 查看文件屬性 print(soda.attrs) # 查看文件中包含的對象 print(soda) {} <xarray.Dataset> Dimensions: (lat: 24, lon: 72, month: 36, year: 100) Coordinates:* year (year) int32 1 2 3 4 5 6 7 8 9 10 ... 92 93 94 95 96 97 98 99 100* month (month) int32 1 2 3 4 5 6 7 8 9 10 ... 28 29 30 31 32 33 34 35 36* lat (lat) float64 -55.0 -50.0 -45.0 -40.0 -35.0 ... 45.0 50.0 55.0 60.0* lon (lon) float64 0.0 5.0 10.0 15.0 20.0 ... 340.0 345.0 350.0 355.0 Data variables:sst (year, month, lat, lon) float32 ...t300 (year, month, lat, lon) float32 ...ua (year, month, lat, lon) float64 ...va (year, month, lat, lon) float64 ... # 查看維度和坐標 print(soda.dims) print(soda.coords) Frozen(SortedKeysDict({'year': 100, 'month': 36, 'lat': 24, 'lon': 72})) Coordinates:* year (year) int32 1 2 3 4 5 6 7 8 9 10 ... 92 93 94 95 96 97 98 99 100* month (month) int32 1 2 3 4 5 6 7 8 9 10 ... 28 29 30 31 32 33 34 35 36* lat (lat) float64 -55.0 -50.0 -45.0 -40.0 -35.0 ... 45.0 50.0 55.0 60.0* lon (lon) float64 0.0 5.0 10.0 15.0 20.0 ... 340.0 345.0 350.0 355.0 # 讀取數據 soda_sst = soda['sst'] print(soda_sst[1, 1, 1, 1], '\n')soda_t300 = soda['t300'] print(soda_t300[1, 2, 12:24, 36], '\n')soda_ua = soda['ua'] print(soda_ua[1, 2, 12:24:2, 36:38], '\n')soda_va = soda['va'] print(soda_va[5:10, 0:12, 12, 36]) <xarray.DataArray 'sst' ()> array(0.549156, dtype=float32) Coordinates:year int32 2month int32 2lat float64 -50.0lon float64 5.0 <xarray.DataArray 't300' (lat: 12)> array([ 0.350308, -0.271906, -0.394029, 0.534374, 0.378115, 0.371367,0.082296, 0.754251, 0.682577, 0.147856, 0.220678, 0.574088],dtype=float32) Coordinates:year int32 2month int32 3* lat (lat) float64 5.0 10.0 15.0 20.0 25.0 ... 40.0 45.0 50.0 55.0 60.0lon float64 180.0 <xarray.DataArray 'ua' (lat: 6, lon: 2)> array([[ 1.222841, 1.084187],[-0.106073, -0.286916],[-0.983318, -0.892802],[-1.157512, -1.04381 ],[ 1.443658, 1.275039],[ 2.179182, 1.776857]]) Coordinates:year int32 2month int32 3* lat (lat) float64 5.0 15.0 25.0 35.0 45.0 55.0* lon (lon) float64 180.0 185.0 <xarray.DataArray 'va' (year: 5, month: 12)> array([[ 0.875687, 0.640397, 1.346922, 0.532989, 0.985298, 1.02812 ,0.853269, 0.746913, 0.289339, -0.401898, -0.832116, -0.432147],[ 0.040508, 0.157661, -0.734164, -0.706849, -0.567588, 0.104219,0.588996, 0.224966, -0.252701, -0.519716, -1.152297, -1.315635],[-1.742571, -2.09365 , -3.080663, -2.863212, -1.135314, 0.053631,0.513007, 1.139938, 1.030276, 1.018402, 0.882338, 2.161939],[ 1.876133, 1.298197, 0.912559, 0.072299, -0.547984, 0.95893 ,1.205327, 0.956807, 0.993742, 0.75878 , 0.690233, 0.910672],[ 0.564618, -0.047889, 0.537964, 0.341526, -0.142936, -0.160385,0.36168 , 0.315495, 0.51516 , 0.513514, 0.066542, 0.423261]]) Coordinates:* year (year) int32 6 7 8 9 10* month (month) int32 1 2 3 4 5 6 7 8 9 10 11 12lat float64 5.0lon float64 180.0作業
基礎作業:
1.嘗試用NetCDF4和Xarray來操作賽題數據,對數據有基本的了解。
進階作業:
2.嘗試用Xarray對訓練數據進行數據探索和數據可視化。
總結
以上是生活随笔為你收集整理的【算法竞赛学习】气象海洋预测-Task1 气象数据分析常用工具的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 沪深股通净流入的意思
- 下一篇: 中国黄金上市时间