ねるねるねるねをねらずにくうぜ

C とかC++(予定)とかpythonとかgnuplotとかmatlabとかmathematicaとか書く予定ですが、最終的にはねるねるねるねをねらずに食うことを目標にしているブログです

HDF5形式のファイル (2) pythonを使った書き出し

さて、前回は、HDF5とはなんぞや、というお話をしました。

今回は、pythonを使って

  • HDF5の中のデータを読み込む
  • HDF5形式でデータを書き出す

ということをしてみましょう。

ちなみに、あのあといろいろ調べてたら、こういうエントリーがありました。

HDF5フォーマットに関するメモ書き - たまに書きます

ここで”HDF5とはなんぞや”について、より詳しく述べてありますし、Cでのインストール方法も書いてありました。参考にしてみてください。

事前準備

  • まず、ここ から、 HDFview をダウンロードしましょう。 自分のマシンの環境にあったものをダウンロードしてください。

さて、これは何か?文字通り、HDF形式(HDF5,HDF4)を読み書きできるアプリケーションです。 まぁ、HDF用のエディタだと思ってくれればいいです。Javaで書いてあるため、ちょっと違和感があるインタフェースかも知れませんが、基本的な使い方は見ればわかると思います。 ひとまずダウンロードしたら、放置でいいです。

普通だったらデモファイル見たいなのがあるかと思いますが、見当たらないので、後で自分でつくってもらいます

  • h5pyのライブラリをダウンロード

このエントリ のクッソ適当な説明をみて、"h5py"をインストールしてくだい。 つまり、

pip search h5py

をして、まだ入ってなかった人は、

pip install h5py

をしてください。 Canopy や Anacondaを使っている人は、package installerを使って"HDF5"で検索しても見つかると思います。

これは、pythonでhdf5を使うためのパッケージです。 こいつのインストールまで終わったら事前準備終了です。

HDF5形式のデータを保存しよう

普通こういうのってでもデータがあって、それを試しにまず見て見るところからスタートすると思うんですが、いかんせん良いデータが見つからんので、今から皆さんに作ってもらいます。

テストデータとして、乱数のスペクトルを解析します。

まずは乱数を作りましょう。 ただし、サンプリング周波数を三種類用意して、同時に作っていきます。

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
sampling_frequency = [10.,100.,1000.]
t= np.zeros((3,100))
sample= np.zeros((3,100))
for i in np.arange(3):
    t[i] = np.arange(0,100.,1)/sampling_frequency[i]
    sample[i] = np.random.normal(size=len(t[i]))
    plt.plot(t[i],sample[i],'o')

このデータのスペクトル(どの周波数が強いか)を調べるために、FFTしてみます。

for i in np.arange(3):
    if i ==0:
        sample_fft =[np.fft.fft(sample[i])]
    else:
        sample_fft =np.r_[sample_fft,[np.fft.fft(sample[i])]]
plt.plot(np.real(sample_fft[0]))
plt.plot(np.imag(sample_fft[0]))
plt.plot(np.abs(sample_fft[0]))

図はサンプリング周波数が10Hzの時のものが出てきます。

それぞれの意味はおいておいて、このグラフで示された青、緑、赤のデータを保存します。

ちょっと考えてみよう

ここはとりあえずHDF5を触ってみたい人は読まなくてもいいです。 興味ない方は、次のHDF5への書き込みに移ってください。 今保存したいデータは、

  • サンプリング周波数(x3個)ごとにある、 1.乱数そのもののデータ 2.フーリエ展開して得られたスペクトル の系6組のデータ・セットです。

各データセットは、100点からなる数値データで構成されています。 これを普通に保存すると、

  • 100点のデータを含む、6個のテキストデータ

が出来上がります。しかしこれらをバラバラに保存しておくのは不便です。 そこで、次のような階層をもたせます

  • [サンプリング周波数]
    • 乱数のサンプル
    • 乱数サンプルのFFT

つまり、3フォルダの中に、二つづつデータセットを入れて保存するのが良さそうです。 しかし、たかだか乱数のフーリエスペクトルごときに、3つもフォルダを作ってデータファイルを6個も作るのはめんどいですよね。

となると、こういうデータはひとつにまとめてしまいたくなります。しかし、無理やり一つのテキストファイルにまとめるのも億劫です。こういう時にHDF5ファイルは威力を発揮します。 というわけで、これをHDF形式のデータファイルとしてまとめて保存しましょう。

HDF5での書き込み

細かい書き込み方の説明は後にするとして、とりあえずこのデータを書き込みましょう。 以下のcodeを実行してください。

import h5py
output_file = "random.h5"
h5file = h5py.File(output_file,'w')
for i in np.arange(3):
    dir = 'frequency_'+str(np.int(sampling_frequency[i]))
    h5file.create_group(dir)
    h5file.create_dataset(dir+'/random_number',data= sample[i])
    h5file.create_dataset(dir+'/spectrum',data= sample_fft[i])
    h5file.flush()
    
h5file.flush()
h5file.close()

"h5py"をインポートするのを忘れないようにしましょう!

また、"h5file.flush()""h5file.close()"は忘れないようにすると後々めんどくなくていいです。

ともかくここまで実行すれば、このipython notebookファイルのあるディレクトリに、"random.h5"が出来上がるはずです。

こいつを右クリックして、"Edit HDF5 file"を選ぶと、HDFviewerが起動し、こんな画面ができます。

左のディレクトリっぽいタグを押してあげれば、"random_number"っていうやつと、"spectrum"っていうやつができているはずです。 これらそれぞれが先ほど生成したデータ・セットの一組に対応します。

というわけで、こんなかんじでディレクトリを含んだデータ・セットが出来上がっているのがわかるでしょう。

何をしているの?

先ほどのpython codeの中の、

dir = 'frequency_'+str(np.int(sampling_frequency[i]))
    h5file.create_group(dir)
    h5file.create_dataset(dir+'/random_number',data= sample[i])
    h5file.create_dataset(dir+'/spectrum',data= sample_fft[i])
    h5file.flush()
    
h5file.flush()
h5file.close()

これらの操作、一体何をしているんでしょうか? 実は、HDF5形式のデータを書き込んでいます。一個づつ説明していきましょう。 より詳しい説明が必要になったら、関数のカッコの内で

[shift]+[TAB]

を何度か押せば説明が出てきます。参照してみてください。

create_group
h5file.create_group(dir)

という操作は、HDF5のファイルの中に、"dir(=frequency_10とか)"というフォルダを作れ!っていう命令です。 言い換えれば、この関数は、"ディレクトリを作れという操作"に対応します HDF5ファイル内では、ディレクトリは"group"と呼ばれており、それを作成するということになります。

create_dataset

次に、

 h5file.create_dataset(dir+'/random_number',data= sample[i])
 h5file.create_dataset(dir+'/spectrum',data= sample_fft[i])

この関数を用いてデータ・セットをHDF5ファイルに書き込みます。 つまり、ディレクトリの中に”データファイル”を作成する操作は、HDF5ではこの関数に対応します

flush,close

忘れがちですが、データ書き込み時に大事なのが、この2つ

h5file.flush()
h5file.close()

普通にオブジェクトのフラッシュ(メモリに蓄えられているデータをファイルに即座に書き込ませる)・クローズ(開いているファイルを閉じさせる)のよくある命令です。

しかし、このh5pyが面倒で、flushを適宜していないまま変なところでエラーで中断してしまうと、pythonがやたらとこのファイルを掴んだまま離さなくなってしまい、一旦pythonを終了しないとデータファイルを消したり、追加で編集できなくなることが有ります。

多数の環境で試したわけではなく、私のところだけなのかもしれませんが、念のためflushやcloseはこまめにしていきましょう。

まとめ

  • pythonでは、h5pyの関数を使ってHDF5のデータを扱う
  • "ディレクトリ作成"は[file_object].create_group([name])
  • "データ書き込み"は[file_object].create_dataset([groupname]+[dataname])
  • flush,closeを忘れずに

次回は、今回作ったデータをいじくってみましょう。