利用python如何处理nc数据详解


Posted in Python onMay 23, 2018

前言

这两天帮一个朋友处理了些 nc 数据,本以为很简单的事情,没想到里面涉及到了很多的细节和坑,无论是“知难行易”还是“知易行难”都不能充分的说明问题,还是“知行合一”来的更靠谱些,既要知道理论又要知道如何实现,于是经过不太充分的研究后总结成此文,以记录如何使用 python 处理 nc 数据。

一、nc 数据介绍

nc 全称 netCDF(The Network Common Data Form),可以用来存储一系列的数组,就是这么简单(参考https://www.unidata.ucar.edu/software/netcdf/docs/netcdf_introduction.html)。

既然 nc 可以用来一系列的数组,所以经常被用来存储科学观测数据,最好还是长时间序列的。

试想一下一个科学家每隔一分钟采集一次实验数据并存储了下来,如果不用这种格式存储,时间长了可能就需要创建一系列的 csv 或者 txt 等,而采用 nc 一个文件就可以搞定,是不是很方便。

更方便的是如果这个科学实验与气象、水文、温度等地理信息稍微沾点边的,完全也可以用 nc 进行存储, GeoTiff 顶多能多存几个波段(此处波段可以认为是气象、水文等不同信号),而 nc 可以存储不同波段的长时间观测结果,是不是非常方便。

可以使用 gdal 查看数据信息,执行:

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 表示记录的是一种格式的数据(气象、水文等等),如果要想查看此 SUBDATASET 的具体信息,可以执行:

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 记录了一个时间点(或者其他区分形式)的一条记录,这个记录是一个数组。

所以看到这里,各位应该已经明白了,可以直接使用 GDAL 处理 nc 数据,比如直接使用 gdalwarp 将某个 SUBDATASET 转成 GeoTiff 等等,此处暂且不表,各位只需要查阅一下 gdalwarp 手册即可知道如何处理。

明白了以上信息基本也就清楚了如何处理此数据。

二、数据处理

python 是运用非常广泛,自然其下各种类库非常丰富,专业一点的说法就叫生态丰富。

2.1 netCDF4

此框架可以直接将 nc 读取成数组(详细信息参考https://github.com/Unidata/netcdf4-python (本地下载))。读取方式如下:

dataset = netCDF4.Dataset('name.nc') # open the dataset

这样即可读出整个 nc 中的数据信息,如果需要获取某个 SUBDATASET 只需要使用 dataset[SUBDATASET_NAME] 即可,返回的是一个三维数组,表示不同时间段(或其他区分方式下)的数据信息。

我们可以对此数组做各种操作,如求平均值、方差等等,又让我想起了大学里的那一堆枯燥但又让人很有兴趣的实验课程。当然,此处如果使用 numpy 框架进行处理,会起到事半功倍的效果,如求长时间序列下的平均值:

np_arr = np.asarray(dataset[SUBDATASET_NAME])
average_arr = np.average(np_arr, axis=0)

到这里跟地信有关的同志都会看出一个问题,此框架只能对数据进行处理,而不能进行与位置有关的操作,这就导致数据无法变成直白的地图可视化效果。其实任何数据都是相通的,我们可以采用此种方式处理完后转为 GeoTiff 等,当然我们也可以直接采用 GeoTiff 的处理流程来进行处理。

2.2 rasterio

rasterio 是 Mapbox 开源的空间数据处理框架,功能非常强大,此处不细说,只表如何处理我们的 nc 数据。

当然第一种方式就是使用 netCDF4 处理完之后,使用此框架写入 GeoTiff,但是这样不太优雅,而且使用了两个框架,明显过于麻烦,我们直接使用此框架从读数据开始处理。

此处读的时候就有技巧了,要像采用 gdalinfo 读取 SUBDATASET 一样来直接读取此 SUBDATASET 数据,如下:

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 函数传入 NETCDF:name.nc:SUBDATASET_NAME,采用 src.read(range(1, dim + 1)) 可以直接读出此范围内所有 Band (时间点)的信息,范围可以自己设定,注意从 0 开始,当然也可以仅读取某个 Band 的信息。

src.meta 记录了此 SUBDATASET 的元数据信息,与 gdalinfo 看到的基本相同。

这样我们就可以继续将此数据使用 numpy 等框架进行处理,处理完之后更重要的是要写入 GeoTiff 中(直白的说就是添加空间信息)。

也很简单,如下即可:

with rio.open(newfile, 'w', **out_meta) as dst:
 dst.write_band(1, res_arr)

newfile 为存储路径,res_arr 为计算结果数组,注意尺寸不要发生变化(width*height),out_meta 为目标文件的元数据描述信息,可以直接将上面 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 表示目标数据空间投影信息,transform 表示目标文件 空间范围信息,可以通过经纬度信息和图像尺寸等计算得到。

dst.write_band 将数据写入对应波段,当然此处也可以写入多个波段,根据计算结果而定,同样从 1 开始。

三、总结

本文简单介绍了 nc 数据的特点及如何使用 python 处理 nc 数据。每个目标都有多条路可以达到,重要的是找到那条自己喜欢的和适合自己的路,然而话又说回来,即使走的不是想要的那条路,不是一样可以达到目标嘛!所以关键是要找到自己的目标。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python urlopen 使用小示例
Sep 06 Python
python对字典进行排序实例
Sep 25 Python
Python3爬虫全国地址信息
Jan 05 Python
浅谈pyqt5在QMainWindow中布局的问题
Jun 21 Python
详解python和matlab的优势与区别
Jun 28 Python
Python正则表达式匹配数字和小数的方法
Jul 03 Python
Python获取时间戳代码实例
Sep 24 Python
python 循环数据赋值实例
Dec 02 Python
详解Python中import机制
Sep 11 Python
Python爬取股票信息,并可视化数据的示例
Sep 26 Python
Python暴力破解Mysql数据的示例
Nov 09 Python
Python数据分析之pandas读取数据
Jun 02 Python
python发送邮件脚本
May 22 #Python
python smtplib发送带附件邮件小程序
May 22 #Python
python SMTP实现发送带附件电子邮件
May 22 #Python
python 获取当天凌晨零点的时间戳方法
May 22 #Python
python 爬虫一键爬取 淘宝天猫宝贝页面主图颜色图和详情图的教程
May 22 #Python
python3.x实现发送邮件功能
May 22 #Python
python 爬虫 批量获取代理ip的实例代码
May 22 #Python
You might like
十大催泪虐心动漫电影,有几部你还没看
2020/03/04 日漫
PHP下MAIL的另一解决方案
2006/10/09 PHP
一些关于PHP的知识
2006/11/17 PHP
PHP 用数组降低程序的时间复杂度
2009/12/04 PHP
PHP字符串与数组处理函数用法小结
2020/01/07 PHP
php模拟实现斗地主发牌
2020/04/22 PHP
jquery.ui.draggable中文文档
2009/11/24 Javascript
获取内联和链接中的样式(js代码)
2013/04/11 Javascript
基于javascript实现全国省市二级联动下拉选择菜单
2016/01/28 Javascript
javascript获取wx.config内部字段解决微信分享
2016/03/09 Javascript
详解Angular的内置过滤器和自定义过滤器【推荐】
2016/12/26 Javascript
javascript实现blob加密视频源地址的方法
2019/08/08 Javascript
vue 中 elment-ui table合并上下两行相同数据单元格
2019/12/26 Javascript
Vue基于localStorage存储信息代码实例
2020/11/16 Javascript
Python装饰器使用示例及实际应用例子
2015/03/06 Python
python使用pil进行图像处理(等比例压缩、裁剪)实例代码
2017/12/11 Python
Python堆排序原理与实现方法详解
2018/05/11 Python
Django组件之cookie与session的使用方法
2019/01/10 Python
理想高通滤波实现Python opencv示例
2019/01/30 Python
使用Flask-Cache缓存实现给Flask提速的方法详解
2019/06/11 Python
关于python 的legend图例,参数使用说明
2020/04/17 Python
python中对二维列表中一维列表的调用方法
2020/06/07 Python
python 中的9个实用技巧,助你提高开发效率
2020/08/30 Python
pycharm-professional-2020.1下载与激活的教程
2020/09/21 Python
实现CSS3中的border-radius(边框圆角)示例代码
2013/07/19 HTML / CSS
深入解析HTML5中的Blob对象的使用
2015/09/08 HTML / CSS
铭立家具面试题
2012/12/06 面试题
国外软件测试工程师面试题
2016/12/09 面试题
电大学习个人自我评价范文
2013/10/04 职场文书
学生实习自我鉴定
2013/10/11 职场文书
对标管理实施方案
2014/03/12 职场文书
临床医学生职业规划书范文
2014/10/25 职场文书
优秀大学生事迹材料
2014/12/24 职场文书
车间班组长竞聘书
2015/09/15 职场文书
关于Numpy之repeat、tile的用法总结
2021/06/02 Python
Python安装及建立虚拟环境的完整步骤
2022/06/25 Servers