Python氣象數據處理進階之Xarray(1):Xarray的數據結構

首先聲明的是前一系列并沒有完結,只是暫時新開一個新系列。關于畫圖部分目前也沒有什么太好的想法,所以暫時擱置,等有想法了會繼續寫下去的。考慮到目前大家最感興趣的還是數據讀取和處理部分,并且這部分也是python處理數據的優勢,因此就專門開一個系列來寫這部分內容。這也是對“Python氣象數據處理與繪圖(1):數據讀取”的深入。按目前的構想,這部分應該是以幾個庫使用為主。首先是數據讀取部分,我使用的是Xarray,因此這個系列也從Xarray的介紹開始。主要內容還是圍繞Xarray的官網文檔進行。

1、Xarray中的數據結構是怎樣的?

在Xarray中,數組是具有結構和標簽的,它們分為以下幾種:

1.DataArray:

帶有標注或命名維度的多維數組。DataArray將metadata(例如維名稱,坐標和屬性)添加到基礎的“未標記”的數據結構,例如numpy和Dask數組。

2.Dataset:

具有類似字典結構的尺寸對齊的DataArray對象的集合。因此,可以在單個DataArray的維度上執行的大多數操作都可以在數據集上執行。

3.Variable:

類似于NetCDF的變量,由dimensions, data, 和 attributes組成。變量和numpy數組之間的主要功能區別在于,對變量的數字運算可以通過維名稱實現數組廣播。

通俗的講Variable< DataArray< Dataset (<指包含于的意思),這樣解釋并不完全準確,但是對于初學者來說這樣理解是沒有問題的。

Xarray中的數據結構是怎樣被識別和標記的呢?

前邊提到,可以通過對維命名的操作實現數據篩選和處理,實現數據的標記和命名是通過以下幾個定義實現的:

1.Dimension:

維,維度的維,比如說在一個二維直角坐標系,維就是x和y,在一個二維圓柱投影地理坐標系,維就是lat和lon,我們通常下載的數據最多也就是四維,即時間維,高度維,緯度維和經度維。

2.Coordinate:

坐標或者說刻度。還是舉例子解釋,比如說Dimension是緯度維,那么對應的Coordinate就是緯度坐標(90°N,89°N,88°N........89°S,90°S)

3.Index:

索引號,也可以說位置標號。a[0]就代表a數組的第一個數,0就是index

這次不舉一個例子,舉一些例子。

#CN05.1格點資料
f = xr.open_dataset('CN05.1_Tmax_1961_2017_daily_05x05.nc')
print(f)
#<xarray.Dataset>
#Dimensions:    (latitude: 82, longitude: 142, time: 20574)
#Coordinates:
#  * longitude  (longitude) float64 69.75 70.25 70.75 71.25 ... 139.2 139.8 140.2
#  * latitude   (latitude) float64 14.75 15.25 15.75 16.25 ... 54.25 54.75 55.25
#  * time       (time) datetime64[ns] 1961-01-01 1961-01-02 ... 2017-04-30
#Data variables:
#    tmax       (time, latitude, longitude) float32 ...
#Attributes:
#    CDI:          Climate Data Interface version 1.6.5rc3 (http://code.zmaw.d...
#    Conventions:  CF-1.4
#    history:      Thu Aug 23 09:34:52 2018: cdo -r remapcon,grid05x05 daily/0...
 #   CDO:          Climate Data Operators version 1.6.5rc3 (http://code.zmaw.d...

我們可以看到,這個文件,是一個dataset,里邊含有變量:Data variables,數據集的維度有經度緯度和時間,各自有各自的坐標Coordinates,同樣數據集還有一些屬性Attributes來表明數據集信息。
我們可以通過:

print(f.variables)
print(f.dims)
print(f.coords)

來分別查看數據集中所含有的變量,維,坐標。
再比如NCEP的位勢高度資料

f = xr.open_dataset('hgt.1948.nc')
print(f)
#<xarray.Dataset>
#Dimensions:  (lat: 73, level: 17, lon: 144, time: 366)
#Coordinates:
#  * level    (level) float32 1000.0 925.0 850.0 700.0 ... 50.0 30.0 20.0 10.0
#  * lat      (lat) float32 90.0 87.5 85.0 82.5 80.0 ... -82.5 -85.0 -87.5 -90.0
#  * lon      (lon) float32 0.0 2.5 5.0 7.5 10.0 ... 350.0 352.5 355.0 357.5
#  * time     (time) datetime64[ns] 1948-01-01 1948-01-02 ... 1948-12-31
#Data variables:
#    hgt      (time, level, lat, lon) float32 ...
#Attributes:
#    Conventions:    COARDS
#    title:          mean daily NMC Reanalysis (1948)
#    description:    Data is from NMC initialized reanalysis\n(4x/day).  It co...
#    platform:       Model
#    history:        created 99/05/11 by Hoop (netCDF2.3)
#    References:  (http://www.esrl.noaa.gov/psd/data/gridded/data.ncep.reana...
#    dataset_title:  NCEP-NCAR Reanalysis 1

基本同上。
需要說明一點的是,ncl中數據存在short格式,在讀取時需要使用short2flt()函數,但是在python中是不存在short格式的,默認均為float,無需考慮這點。

如何創建一個DataArray?

有時候我們可能通過其他手段讀取了相關數據,但是數據是np.array格式的,我們需要將其轉換為DataArray,亦或者我們需要輸出一個NC文件,需要將計算后的數組轉為DataArray格式,這就用到了創建的方法。

創建一個DataArray需要什么?
1.Data

廢話,創建數據當然需要數據啦。數據可以是numpy ndarray,series,DataFrame等等格式的

2.coords:坐標列表或字典

如果是列表,則應為元組列表,其中第一個元素是維名稱,第二個元素是對應的坐標array_like對象。個人建議用字典結構去定義

3.dims:維名稱列表

如果省略,并且coords是元組列表,則維度名稱取自coords。

4.attrs:屬性
5.name:變量名

以上除了data以外,都不是必須的。
創建如下:

data = np.array([[1,2,3],[4,5,6]])
level = ['500', '850', '1000']
times = pd.date_range('2000-01-01', periods=2)
foo = xr.DataArray(data, coords=[times, level], dims=['time', 'level'])
print(foo)
#<xarray.DataArray (time: 2, level: 3)>
#array([[1, 2, 3],
#       [4, 5, 6]])
#Coordinates:
#  * time     (time) datetime64[ns] 2000-01-01 2000-01-02
#  * level    (level) <U4 '500' '850' '1000'

例子基本于官網一致,對標簽略作了修改,level更加便于氣象專業的理解。
剛剛說了,除了data以外,其他都是不必要的

foo = xr.DataArray(data)
print(foo)
#<xarray.DataArray (dim_0: 2, dim_1: 3)>
#array([[1, 2, 3],
#       [4, 5, 6]])
#Dimensions without coordinates: dim_0, dim_1

如果我們是從一個DataFrame數據轉化為DataArray的話(這種操作通常是為了將Pandas和Xarray聯合使用):

df = pd.DataFrame({'x': [0, 1], 'y': [2, 3]}, index=['a', 'b'])
df.index.name = 'abc'
df.columns.name = 'xyz'
print(df)
#xyz  x  y
#abc      
#a    0  2
#b    1  3
print(xr.DataArray(df))
#<xarray.DataArray (abc: 2, xyz: 2)>
#array([[0, 2],
#       [1, 3]])
#Coordinates:
#  * abc      (abc) object 'a' 'b'
#  * xyz      (xyz) object 'x' 'y'

會自動識別行列的名稱和序號。
官方文檔還給出了更復雜的實例,但是個人感覺很少用到,因此不寫在這里了,通常用以上的例子可以完成大部分操作了。
在創建了數據之后,我們同樣可以使用相關的操作獲取DataArray的各種信息:

a = foo.values
a = foo.dims
a = foo.coords
a = foo.attrs

如果想對DataArray的值進行修改可以通過以下兩種方法:

foo.values = foo.values +2
foo = foo +2

目前測試結果兩者是等價的,但是我不知道官方為什么沒給出第二種方法。
通過指令

foo.attrs['units'] = 'meters'

賦予屬性信息,比如說給一個單位,備注等等。
通過指令

foo.name = 'hgt'

賦予名稱信息
通過指令:

foo.rename('temperature')

改名,比如說通過hgt計算得到了一個新變量,需要改名,就可以用這個指令了。

在得到了一個DataArray之后,用于畫圖時,比如說我們需要獲取他的經度和緯度(在這里,剛剛的例子是時間和高度),
那么可以直接通過

foo.coords['time']
foo['time']

這兩種方式取出坐標信息。
要修改或者刪除某坐標信息的話,原理和修改數據是一樣的:

foo['time'] = pd.date_range('1999-01-02', periods=2)
del foo['time']

如何創建一個Dataset?

官網給出了一個以氣候數據為例的Dataset結構:


Dataset結構

一個數據集,包含了數據主體(Temperature, Precipitation),維度坐標(latitude,longitude)

根據官網的例子,一個Dataset是這樣創建的,其實與DataArray類似:

temp = 15 + 8 * np.random.randn(2, 2, 3)
precip = 10 * np.random.rand(2, 2, 3)
lon = [[-99.83, -99.32], [-99.79, -99.23]]
lat = [[42.25, 42.21], [42.63, 42.59]]

ds = xr.Dataset({'temperature': (['x', 'y', 'time'],  temp),
                 'precipitation': (['x', 'y', 'time'], precip)},
                coords={'lon': (['x', 'y'], lon),
                        'lat': (['x', 'y'], lat),
                        'time': pd.date_range('2014-09-06', periods=3),
                        'reference_time': pd.Timestamp('2014-09-05')})
#<xarray.Dataset>
#Dimensions:         (time: 3, x: 2, y: 2)
#Coordinates:
#    lon             (x, y) float64 -99.83 -99.32 -99.79 -99.23
#    lat             (x, y) float64 42.25 42.21 42.63 42.59
#  * time            (time) datetime64[ns] 2014-09-06 2014-09-07 2014-09-08
#    reference_time  datetime64[ns] 2014-09-05
#Dimensions without coordinates: x, y
#Data variables:
#    temperature     (x, y, time) float64 15.09 7.656 20.82 ... 2.477 10.53 17.56
#    precipitation   (x, y, time) float64 3.444 2.694 6.921 ... 7.351 2.099 5.972

實際上這個例子與我們通常接觸的不太一樣,因為大部分的數據的lat和lon是一個一維的。
對Dataset的操作與DataArray基本是一致的,就不重復了。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容