HDF5形式のファイル (2) pythonを使った書き出し
さて、前回は、HDF5とはなんぞや、というお話をしました。
今回は、pythonを使って
- 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]))
それぞれの意味はおいておいて、このグラフで示された青、緑、赤のデータを保存します。
ちょっと考えてみよう
ここはとりあえず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を忘れずに
次回は、今回作ったデータをいじくってみましょう。