Python处理NetCDF数据入门
前言
在前面做极值分析、气象数据可视化等的时候,我们主要用的是csv格式存储数据,而在气象科学等领域中,还有一种十分重要的数据格式——NetCDF。在本篇文章里,我们将简要介绍NetCDF以及如何用Python处理NetCDF文件。
NetCDF简介
NetCDF(Network Common Data Form),即网络通用数据格式,是一种自描述、与机器无关、基于数组的科学数据格式,同时也是支持创建、访问和共享这一数据格式的函数库。NetCDF于1989年由美国大气科学研究大学联盟(UCAR)开发,最新版本为4.x(详见 项目主页)。NetCDF格式是一种开放标准,其经典格式和64位偏移量格式是开放地理空间协会采用的国际标准。
netCDF常用于气候学、气象学、海洋学等领域,如天气预报、气候变化等;也应用于地理信息系统,是许多GIS应用的输入输出格式。NCEP(美国国家环境预报中心)发布的再分析资料,NOAA的CDC(气候数据中心)发布的海洋与大气综合数据集(COADS)均采用NetCDF作为标准。NetCDF的广泛应用,在很大程度上得益于其灵活性,而它的灵活性则要归功于“自描述”的特点。
所谓“自描述”是指,数据本身包含了相关的数据描述信息,它有一个头部,描述文件余下部分的格局,特别是数组数据,连同以名称/值属性形式的任意文件元数据。程序自动判断维和变量等信息的前提条件是数据必须遵循某种约定(convensions)。气象上最常用的约定是气候和预报预定(Climate and Forecast (CF) conventions),对于维、变量、属性有详细的规定,这样以来软件才能通过约定对数据进行正确的判读。
更多关于NetCDF的介绍,参见这里。
Python处理NetCDF
由于NetCDF格式的流行,处理NetCDF数据的软件也层出不穷,既有开源、免费的,也有需要商业授权的,NetCDF项目网站上列出了许多可用的软件包:
当然,我们关心的是Python下处理NetCDF的库,常用的有以下三个:
netCDF4
, http://unidata.github.io/netcdf4-python/iris
, http://scitools.org.uk/irisxarray
,https://www.scipy.org/
接下来,我们将用由NOAA提供的全球2018年日最高气温的NetCDF文件(https://www.esrl.noaa.gov/psd/repository/entry/show )作为示例,介绍三个库的使用。
1 | sample_file = 'tmax.2018.nc' |
netCDF4
netCDF4,顾名思义可知,是一个用于处理NetCDF数据的专用库。netCDF4是一个在GIS中常用的库,我们之前在地理数据可视化的工作中曾经安装过,作为一个基本库,是其他一些库的依赖。netCDF4的功能比较简单,相对于其他的库(例如xarray)没有一些花里花哨的东西,反而提供了一些底层功能的易用性。
1 | import netCDF4 |
<class 'netCDF4._netCDF4.Dataset'>
root group (NETCDF4_CLASSIC data model, file format HDF5):
Conventions: CF-1.0
Source: ftp://ftp.cpc.ncep.noaa.gov/precip/wd52ws/global_temp/
version: V1.0
title: CPC GLOBAL TEMP V1.0
dataset_title: CPC GLOBAL TEMP
References: https://www.esrl.noaa.gov/psd/data/gridded/data.cpc.globaltemp.html
history: Updated 2019-01-28 17:21:38
dimensions(sizes): lat(360), lon(720), time(365)
variables(dimensions): float32 [4mlat[0m(lat), float32 [4mlon[0m(lon), float64 [4mtime[0m(time), float32 [4mtmax[0m(time,lat,lon)
groups:
我们可以像访问词典的方式访问其中的数据,并且查看“变量”、“属性”等信息:
1 | print(data.dimensions) |
OrderedDict([('lat', <class 'netCDF4._netCDF4.Dimension'>: name = 'lat', size = 360
), ('lon', <class 'netCDF4._netCDF4.Dimension'>: name = 'lon', size = 720
), ('time', <class 'netCDF4._netCDF4.Dimension'> (unlimited): name = 'time', size = 365
)])
OrderedDict([('lat', <class 'netCDF4._netCDF4.Variable'>
float32 lat(lat)
actual_range: [ 89.75 -89.75]
long_name: Latitude
units: degrees_north
axis: Y
standard_name: latitude
coordinate_defines: center
unlimited dimensions:
current shape = (360,)
filling on, default _FillValue of 9.969209968386869e+36 used
), ('lon', <class 'netCDF4._netCDF4.Variable'>
float32 lon(lon)
long_name: Longitude
units: degrees_east
axis: X
standard_name: longitude
actual_range: [2.5000e-01 3.5975e+02]
coordinate_defines: center
unlimited dimensions:
current shape = (720,)
filling on, default _FillValue of 9.969209968386869e+36 used
), ('time', <class 'netCDF4._netCDF4.Variable'>
float64 time(time)
long_name: Time
units: hours since 1900-01-01 00:00:00
axis: T
standard_name: time
coordinate_defines: start
delta_t: 0000-00-01 00:00:00
avg_period: 0000-00-01 00:00:00
actual_range: [1034376. 1043112.]
unlimited dimensions: time
current shape = (365,)
filling on, default _FillValue of 9.969209968386869e+36 used
), ('tmax', <class 'netCDF4._netCDF4.Variable'>
float32 tmax(time, lat, lon)
missing_value: -9.96921e+36
units: degC
level_desc: Surface
statistic: Mean
parent_stat: Other
long_name: Daily Maximum Temperature
cell_methods: time: mean
valid_range: [-90. 50.]
avg_period: 0000-00-01 00:00:00
dataset: CPC Global Temperature
comments: GTS data and is gridded using the Shepard Algorithm
max_period: 6z to 6z
var_desc: Maximum Temperature
actual_range: [-58.620934 53.65277 ]
unlimited dimensions: time
current shape = (365, 360, 720)
filling on, default _FillValue of 9.969209968386869e+36 used
)])
1 | tmax= data.variables['tmax'] |
Variable:
<class 'netCDF4._netCDF4.Variable'>
float32 tmax(time, lat, lon)
missing_value: -9.96921e+36
units: degC
level_desc: Surface
statistic: Mean
parent_stat: Other
long_name: Daily Maximum Temperature
cell_methods: time: mean
valid_range: [-90. 50.]
avg_period: 0000-00-01 00:00:00
dataset: CPC Global Temperature
comments: GTS data and is gridded using the Shepard Algorithm
max_period: 6z to 6z
var_desc: Maximum Temperature
actual_range: [-58.620934 53.65277 ]
unlimited dimensions: time
current shape = (365, 360, 720)
filling on, default _FillValue of 9.969209968386869e+36 used
Attribute:
degC
(720,)
Iris
与netCDF4采用类似字典的方式访问数据不同,Iris则是基于CF约定,采用类似list的方式实现了数据的访问。Iris可以识别多种文件格式,包括符合CF约定的NetCDF、GRIB和PP等,并且可以通过插件扩展添加其他格式。
由于Iris要求matplotlib<3,与我其他的包不兼容,也不想再弄虚拟环境,所以就不再写代码了。
xarray
xarray是我们要介绍的主角。个人感觉xarray
库应该是目前用于处理NetCDF数据最为方便的库了:xarry有两个核心数据结构:DataArray
和Dataset
,xarray可以看作是对Numpy和pandas的扩展,同时也借鉴了许多pandas的优点,具有良好的易用性。xarray与netCDF4在使用上存在许多相似之处,但是从输出的结果我们可以发现,同样是Dataset
,xarray的结果显然有更好的可读性。
1 | import xarray |
<xarray.Dataset>
Dimensions: (lat: 360, lon: 720, time: 365)
Coordinates:
* lat (lat) float32 89.75 89.25 88.75 88.25 87.75 87.25 86.75 86.25 ...
* lon (lon) float32 0.25 0.75 1.25 1.75 2.25 2.75 3.25 3.75 4.25 4.75 ...
* time (time) datetime64[ns] 2018-01-01 2018-01-02 2018-01-03 ...
Data variables:
tmax (time, lat, lon) float32 ...
Attributes:
Conventions: CF-1.0
Source: ftp://ftp.cpc.ncep.noaa.gov/precip/wd52ws/global_temp/
version: V1.0
title: CPC GLOBAL TEMP V1.0
dataset_title: CPC GLOBAL TEMP
References: https://www.esrl.noaa.gov/psd/data/gridded/data.cpc.globa...
history: Updated 2019-01-28 17:21:38
1 | # Variables can be assessed either as properties or as a dict |
Variable:
<xarray.DataArray 'tmax' (time: 365, lat: 360, lon: 720)>
[94608000 values with dtype=float32]
Coordinates:
* lat (lat) float32 89.75 89.25 88.75 88.25 87.75 87.25 86.75 86.25 ...
* lon (lon) float32 0.25 0.75 1.25 1.75 2.25 2.75 3.25 3.75 4.25 4.75 ...
* time (time) datetime64[ns] 2018-01-01 2018-01-02 2018-01-03 ...
Attributes:
units: degC
level_desc: Surface
statistic: Mean
parent_stat: Other
long_name: Daily Maximum Temperature
cell_methods: time: mean
valid_range: [-90. 50.]
avg_period: 0000-00-01 00:00:00
dataset: CPC Global Temperature
comments: GTS data and is gridded using the Shepard Algorithm
max_period: 6z to 6z
var_desc: Maximum Temperature
actual_range: [-58.620934 53.65277 ]
Attribute:
degC
1 | import matplotlib.pyplot as plt |
在xarray中,调用DataArray的plot()
方法可以作图,而且根据数据维数的不同会绘制不同类型的图:
1 | tmax.plot(bins=50) |
我们可以看一下北京(39.9042° N, 116.4074° E)附近网格的2018年的日最高气温情况,可以看到该网格2018年的日最高气温的最大值也就是年最高气温出现在6月29日,温度为39.73摄氏度。
1 | import numpy as np |
1 | tmax.isel(time=0).plot() |
1 | ax={} |
1 | import os |
此外,我们也可以用cartopy作出更加精美的图:
1 | import cartopy.crs as ccrs |
小结
本文简单介绍了地理、气象科学中常用的NetCDF数据格式,以及如何使用Python尤其是xarray
库处理NetCDF数据。当然,我们目前做的只是非常初步的工作,接下来或许可以尝试以其他气象指标(例如厄尔尼诺?)等例进行分析。