NAStools, NASA Ames フォーマット用ツール

NASA Ames Format for Data Exchange というデータ形式があって、 地球科学関係の分野でよく使われている。

このフォーマットを扱える Python パッケージはないものかと PyPI を 探したところ、 2つ見つかった。

nappy:NASA Ames を NetCDF に変換したりする機能があるようで、 インストールに NetCDF のライブラリが必要で面倒なので 後回し。
NAStools:FFI 1001 しか対応していないようだが、職場には 1001 の データしか無いようなので問題なし。

という訳でまず NAStools から試す。

NAStools 試用

virtualenv 関係は省略。

依存パッケージ含めてインストール。

$ pip install numpy
$ pip install pandas
$ pip install NAStools

クイックガイド を参考に使ってみる。サンプルデータは ここ から拾った。

$ curl -O http://badc.nerc.ac.uk/help/formats/NASA-Ames/example-1001-a.na
$ python
>>> import nastools
>>> ex = nastools.Naspy("example-1001-a.na")
>>> ex
NAS Data File (FFI = 1001)
example-1001-a.na

データファイルのヘッダの内容は Naspy.header に格納される。

>>> dir(ex.header)
['COLUMN_VARIABLES', 'DATA_DESCRIPTION', 'DATA_INTERVAL',
'DEPENDENT_VARIABLE', 'FFI', 'FILENAME', 'FILE_VOL_NO', 'HEADER_LINES',
'INDEPENDENT_VARIABLE', 'MISSING_DATA_FLAGS', 'MISSION', 'NORMAL_COMMENTS',
'NORMAL_COMMENT_LINES', 'NO_VOL', 'ORGANIZATION', 'PI', 'REV_UTC',
'SCALE_FACTORS', 'SPECIAL_COMMENTS', 'SPECIAL_COMMENT_LINES', 'START_UTC',
'TOTAL_NUM_VARIABLES', '__class__', '__delattr__', '__dict__', '__doc__',
'__format__', '__getattribute__', '__hash__', '__init__', '__module__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'_fileAbsPath_', '_fileObj_', 'contact_info', 'data_description',
'parse_header']

各属性の内容は属性名を見れば判るだろう。

クイックガイドには Naspy.header.INSTRUMENT_INFO という属性がある ことになっているが、最新版では Naspy.header.DATA_DESCRIPTION に 変わったようだ。

>>> ex.header.DATA_DESCRIPTION
'Meteorological sensors'

Naspy.header.COLUMN_VARIABLES は、 normal comment の最終行が、データのカラム数と同じ個数に split できると その内容が格納される、という仕様のようだ。 なお、ファイルを編集してコメント最終行の構造を壊すと、header オブジェクトに この属性自体がセットされなかった。

>>> print ex.header.COLUMN_VARIABLES
['t', 'T', 'p', 'RH']

似たような機能に Naspy.get_column_names() があるが、こちらは アルファベットを勝手に大文字化してしまう。

>>> print ex.get_column_names()
['T', 'T', 'P', 'RH']

クイックガイドには Naspy.time に関する記述があるが、 Naspy.time.start_time() も Naspy.time.end_time() も動作しなかった。

データ部分は numpy で扱える。

>>> ex.make_numpy()
array([(38927.0, 10.0, 99.0, 0.6), (38927.020833, 10.1, 98.9, 0.591),
       (38927.041667, 9.5, 99.3, 0.62), (38927.0625, 9.2, 99.5, 0.632),
       (38927.083333, 9.3, 99.4, 9.999), (38927.104167, 8.9, 99.9, 9.999),
       (38927.125, 8.5, 100.1, 0.632), (38927.145833, 8.9, 99.8, 0.622),
       (38927.166667, 9.4, 99.7, 0.61), (38927.1875, 10.1, 99.5, 0.604),
       (38927.208333, 10.2, 99.3, 0.595), (38927.229167, 10.4, 99.0, 0.58),
       (38927.245, 10.3, 99.2, 0.587)],
      dtype=[('T', '<f8'), ('T_1', '<f8'), ('P', '<f8'), ('RH', '<f8')])

依存パッケージの pandas は時系列解析のパッケージらしいので、 もしかしたら簡単な解析もできるのかも知れない。 後で調べてみよう。