HDFで取り扱うDataTypeについての備忘録

###はじめに
HDFではDataを格納する際、numpyのdatatypeを指定する必要があります。numpyのデータ型とHDFのデータ型について以下の記事を参考に備忘録として記載します。

###Numpyでのdatatypeについて
[NumPyのデータ型dtype一覧とastypeによる変換（キャスト）](https://note.nkmk.me/python-numpy-dtype-astype/)に詳しい解説が書かれていますので、その中から今回用いる部分について引用します。一部加筆しています。
numpyでdtypeの書き方はいくつかあります。
> 各種メソッドの引数でデータ型`dtype`を指定するとき、例えば`int64`型の場合は、
> （1） データ型：`np.int64`　
> （2） 文字列型：`'int64'`
> （3）型コード型：`'i8'`
> データ型名の末尾の数字は`bit`で表し、型コード末尾の数字は`byte`で表す。同じ型でも値が違うので注意。（8bit=1byte)
>
> ```python
> import numpy as np
> 
> a = np.array([1, 2, 3], dtype=np.int64)
> print(a.dtype)
> # int64
> 
> a = np.array([1, 2, 3], dtype='int64')
> print(a.dtype)
> # int64
> 
> a = np.array([1, 2, 3], dtype='i8')
> print(a.dtype)
> # int64
> ```


>ビット精度の数値を省略して`int`や`float`, `str`のようなPythonの型で指定することもできる。
>
>この場合、等価な`dtype`に自動的に変換されるが、どの`dtype`に変換されるかは環境（Python2かPython3か、32ビットか64ビットかなど）によって異なる。
>
>以下の例はPython3、64ビット環境のもの。`uint`というPythonの型はないが便宜上まとめて挙げておく。
>
>| Pythonの型 | 等価な`dtype`の例 |
>| ---------- | ----------------- |
>| `int`      | `int64`           |
>| `float`    | `float64`         |
>| `str`      | `unicode`         |
>| (`uint`)   | `uint64`          |
>
>引数で指定する場合は`int`でも文字列`'int'`でもOK。Pythonの型ではない`uint`は文字列`'uint'`のみ可。
>
>```python
>print(int is np.int)
># True
>
>a = np.array([1, 2, 3], dtype=int)
>print(a.dtype)
># int64
>
>a = np.array([1, 2, 3], dtype='int')
>print(a.dtype)
># int64
>```
>
>
>
>####主要なデータ型と型コード一覧（上記HPより引用）
>
>| データ型`dtype` | 型コード | 説明                                                         |
>| --------------- | -------- | ------------------------------------------------------------ |
>| `int8`          | `i1`     | 符号あり8ビット整数型                                        |
>| `int16`         | `i2`     | 符号あり16ビット整数型                                       |
>| `int32`         | `i4`     | 符号あり32ビット整数型                                       |
>| `int64`         | `i8`     | 符号あり64ビット整数型                                       |
>| `uint8`         | `u1`     | 符号なし8ビット整数型                                        |
>| `uint16`        | `u2`     | 符号なし16ビット整数型                                       |
>| `uint32`        | `u4`     | 符号なし32ビット整数型                                       |
>| `uint64`        | `u8`     | 符号なし64ビット整数型                                       |
>| `float16`       | `f2`     | 半精度浮動小数点型（符号部1ビット、指数部5ビット、仮数部10ビット） |
>| `float32`       | `f4`     | 単精度浮動小数点型（符号部1ビット、指数部8ビット、仮数部23ビット） |
>| `float64`       | `f8`     | 倍精度浮動小数点型（符号部1ビット、指数部11ビット、仮数部52ビット） |
>| `float128`      | `f16`    | 四倍精度浮動小数点型（符号部1ビット、指数部15ビット、仮数部112ビット） |
>| `complex64`     | `c8`     | 複素数（実部・虚部がそれぞれ`float32`）                      |
>| `complex128`    | `c16`    | 複素数（実部・虚部がそれぞれ`float64`）                      |
>| `complex256`    | `c32`    | 複素数（実部・虚部がそれぞれ`float128`）                     |
>| `bool`          | `?`      | ブール型（`True` or `False`）                                |
>| `unicode`       | `U`      | Unicode文字列                                                |
>| `object`        | `O`      | Pythonオブジェクト型                                         |
>Unicodeの型コードの後は文字数を指定する。

この他にも型コードとして
参考：[Numpy dtype](https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html)

| 型コード | 説明                 |
| -------- | -------------------- |
| b        | (signed) byte        |
| B        | unsigned byte        |
| m        | timedelta            |
| M        | datetime             |
| S, a     | zero-terminated bytes |
| V        | raw data (void)      |


例として

```Python
dt = np.dtype('i4')   # 32-bit signed integer
dt = np.dtype('f8')   # 64-bit floating-point number
dt = np.dtype('c16')  # 128-bit complex floating-point number
dt = np.dtype('a25')  # 25-length zero-terminated bytes
dt = np.dtype('U25')  # 25-character string
dt = np.dtype((np.void, 10))  # 10-byte wide data block　np.dtype('V10')と同じ
dt = np.dtype(('U', 10))   # 10-character unicode string　np.dtype('U10')と同じ
```

>#####文字列について
>`str`や`unicode`などで文字列として指定する場合の`dtype`は`<U1`のようになる。
>
>```python
>a_str = np.array([1, 2, 3], dtype=str)
>print(a_str)
>print(a_str.dtype)
># ['1' '2' '3']
># <U1 
># 1文字
>
>a_str[0] = 'abcde'
>print(a_str)
># ['a' '2' '3']
>#1文字だけ格納。後は切り捨て。
>
>a_str10 = np.array([1, 2, 3], dtype='U10')
>print(a_str10.dtype)
># <U10
>#10文字格納できる。
>
>a_str10[0] = 'abcde'
>print(a_str10)
># ['abcde' '2' '3']
>#10文字以下なのですべて格納される。
>```
>先頭の`<`, `>`は、それぞれリトルエンディアン、ビッグエンディアンを表している。ほとんどの場合、特に気にする必要はない。

>末尾の数字は文字数を表し、この例のようにコンストラクタで`dtype`を`str`や`unicode`と指定した場合、要素の中で最大の文字数となる。

>それぞれの要素に対してこの文字数分のメモリしか確保されていないので、それ以上の文字数の文字列は保持できず切り捨てられる。あらかじめ十分な文字数の型を指定しておけばOK。

###HDFの型と対応するNumpyの型

HDFで扱うDatatypeに対応するnumpyのdatatypeは以下のようになります。
HDF5についての書籍「Python and HDF5: Unlocking Scientific Data」 Chapter7の表からの引用一部加筆しています。
その他に参考になったのが、
[意外と奥が深い、HDFの世界（Python・h5py入門）](https://qiita.com/simonritchie/items/23db8b4cb5c590924d95)



| HDF Type               | Numpy Data Type                                              | 説明                                            |
| ---------------------- | ------------------------------------------------------------ | ----------------------------------------------- |
| Integer                | dtype("i")                                                   | (signed) integer                                |
| Float                  | dtype("f")                                                   | floating-point                                  |
| String(fixed width)    | dtype("S10") or dtype("U10")                                 | S10：10文字(ASCII文字） 、U10：ユニコード10文字 |
| String(variable width) | h5py.special_dtype(vlen=str)　h5py.string_dtype(encoding='utf-8') | numpyには可変長タイプはないためHDFの型指定      |
| Compound               | dtype([("field1":("i")),("field2":"f")])                     | 上記、参考を参照                                |
| Enum                   | hypy.special_dtype(enum=("i",{"RED":0,"GREEN":1,"BLUE":2}))  | 上記、参考を参照                                |
| Array                  | dtype("(2,2)f")                                              | (2x2)でfloat型                                  |
| Opaque                 | dtype("V10")                                                 | raw data (void) 10byte                          |
| Refernece              | h5py.special_dtype(ref=h5py.Reference)                       | HDFの型指定                                     |



### HDF5のサンプルコード
各データタイプ別のサンプルコードは以下のHPにあります。
int型やFloat型の他に Compound Datatypes、Enumerated 、Object References、 Opaque Datatypes、Variable Length Datatypeなど普段あまり使わない型の例も乗っています。
[HDF5 Python Examples by API](https://support.hdfgroup.org/HDF5/examples/api18-py.html#dset)
文字列以外のBinaryデータ（例えば、ディスクイメージやほかの数値ではないバイナリーデータ）はOpaqueTypeを使うのが良いようです。