本文へスキップ
AZ Tools

NumPy .npy / .npz インスペクター

.npy はごく小さなヘッダーの後ろに数値の生ブロックが続くだけのファイルで、このツールが必要とするのはそのヘッダーだけです。マジック 6 バイト、バージョン、ヘッダー長、そして descr・fortran_order・shape を持つ Python の dict リテラル。JSON では ありません。先頭 1KB しか読まないので、2GB の配列も 2KB のファイルと同じ速さで開きます。読み込む価値があるかを決める前に中身を知る、というのがこのツールの目的です。descr は numpy と同じ読み方で解釈します。先頭の 1 文字はバイト順で、< がリトル、> がビッグ、| は該当なし。ビッグエンディアンのファイルには印を付けます。誤読してもエラーには見えず、単に別の数値が出てくるだけだからです。続いて種類と要素サイズ。b1 の真偽値、i1〜i8 と u1〜u8 の整数、f2・f4・f8 の実数、c8・c16 の複素数、内部の NUL は残し末尾の NUL だけを落とす S<n>、UCS-4 で保存されるため 3 文字が 12 バイトを占める U<n>、単位を角括弧に書く M8・m8、生の V<n>、そして O。O は allow_pickle=True で書かれたという意味であり、読み込むと pickle が実行されるという意味なので、目立つ形で警告します。構造化 dtype は (名前, 形式) または (名前, 形式, shape) のタプルの並びとして届き、入れ子にもなります。オフセットはどこにも保存されておらず要素サイズの累積和にすぎません。アラインされた dtype の descr に名前のないパディングフィールドが入っているのはそのためで、それも区間付きで表示します。以降の数値は自分で検算できます。shape から要素数、要素数×要素サイズから想定バイト数、そしてヘッダーの後ろに実在するバイト数。コピー失敗やディスク不足で切れたファイルは、もっともらしいヘッダーではなく不足バイト数として現れます。単純な数値 dtype はファイル上の並び順のまま先頭の値をブラウザ内でデコードするので、Fortran 順の配列は列ごとに読み出されます。.npz は .npy メンバーを収めた zip で、メンバーごとの dtype・shape・二種類のサイズと圧縮の有無を並べます。やらないことも明確です。pickle は展開しませんし、数値の意味も教えませんし、データが壊れていないかも検証しません。ファイル自身の主張と、その主張がサイズと食い違う箇所を示すだけです。

使い方

  1. .npy か .npz をボックスにドロップしてください。ヘッダーしか読まないのでファイルサイズは関係ありません。
  2. まず dtype、shape、要素数を見ます。「中身は何か」への答えであり、読み取り 1 回で済みます。
  3. 想定データ量と実データ量を比べます。少なければ途中で切れており、多ければ配列の後ろに何かが足されています。
  4. 構造化 dtype ならフィールド表を開きます。アラインされた dtype が挿入する無名パディングまで、形式・オフセット・サイズが並びます。
  5. .npz ならメンバー名をクリックしてその配列を調べます。一覧には圧縮後と展開後の両方のサイズが出ます。

よくある質問

.npy のヘッダーには正確には何が入っていますか?
マジック 6 バイト(\x93NUMPY)、2 バイトのバージョン、ヘッダー長、そしてヘッダー本体です。本体は descr・fortran_order・shape のちょうど 3 キーを持つ Python の dict リテラルで、JSON ではないので JSON.parse では読めません。文字列はシングルクォート、真偽値は True と False、shape は (3) ではなく (3,) と書くタプル、閉じ波括弧の前には余分なカンマが付きます。そのうえで配列データが 64 バイト境界から始まるよう空白で埋められます。numpy がアラインされたロードでファイルをメモリマップできるのはこのパディングのおかげです。このツールは descr をファイルに書かれたまま表示するので、途中で正規化されたのではと疑う必要がありません。
文字列配列が文字数の 4 倍もあるのはなぜですか?
numpy の U dtype が UCS-4 で保存するからです。どんな文字でも固定 4 バイトなので、要素サイズは宣言した長さの 4 倍になります。U32 のフィールドは値がすべて "ok" でも 1 要素あたり 128 バイトを使います。バイト列 S は 1 文字 1 バイトですが別の落とし穴があります。読み込み時に末尾の NUL が取り除かれるため、本当に 0 バイトで終わる値は往復できません。内部の NUL はそのまま残ります。データセットが想定外に大きいときはたいてい U dtype が原因で、対処は文字コードを決めて S で保存するか、文字列を別の配列に分けることです。
dtype が object と出ます。どういう意味で、なぜ警告が出るのですか?
object 配列は値ではなくポインタを保存します。そのため保存時に numpy が全体を pickle で直列化し、読み込み時に復元します。復元はパースではありません。任意のオブジェクトを構築し任意のコードを呼べます。numpy.load が allow_pickle=True なしでは object 配列を拒否するのはそのためです。descr が |O の .npy はデータであると同時にプログラムでもあり、その安全性は書いた人の安全性と同じです。このページは pickle を決して展開せず、dtype と pickle のサイズだけを示して止まります。中身が普通の文字列や不揃いのリストなら、固定幅 dtype か .npz の複数配列に書き直す価値があります。
fortran_order は何を変えるのですか?
同じ数値がファイルに並ぶ順序だけです。False なら最後の軸が最も速く変わり(C、行優先)、True なら最初の軸が最も速く変わります(列優先)。np.asfortranarray を通したデータや Fortran・MATLAB 由来のデータがそれです。shape も dtype もどちらでも同一なので、このフラグを無視したリーダーは失敗しません。代わりに配列を黙って転置します。例外が出るよりずっと悪い結果です。ここのプレビューは論理配置ではなくファイルの並びに従うので、Fortran 順の 2×3 配列は 0 列、1 列、2 列の順に読み出されます。
フォーマットのバージョンが 3 つあるのはなぜですか?
1.0 はヘッダー長を 2 バイトに収めるためヘッダーが 65535 バイトに制限されます。2.0 はそれで足りない稀な場合に 4 バイトを使います。フィールドが数千ある構造化 dtype がそれで、ヘッダーは数百 KB にもなります。3.0 は 2.0 と同じですがヘッダーを Latin-1 ではなく UTF-8 と宣言するもので、Latin-1 に無い文字がフィールド名にあるときだけ numpy が書きます。numpy は常に収まる最小のバージョンを選ぶので、2.0 や 3.0 であること自体が情報になります。もう一つ、numpy のローダーは max_header_size を上げない限り 10000 バイトを超えるヘッダーを拒否します。正当な 2.0 ファイルが Python では開けず、ここでは開けることがあります。
ファイルはアップロードされますか? 巨大な配列も開けますか?
アップロードはしませんし、開けます。ブラウザの File API でスライスだけを読みます。ヘッダー用の 1KB 程度と、値のプレビュー用の数 KB だけです。2GB の配列をメモリに載せることはありません。まさにその場面のためのツールです。誰かにファイルを渡され、dtype と shape が知りたいだけなのに、実際に読み込めば数分と RAM の大半を使ってしまう、という場面です。.npz ではファイル末尾の zip ディレクトリと各メンバーのヘッダーしか読まないので、一覧表示は読み取り 2 回+メンバー 1 回ずつで済みます。何も送信しないため、ページを開いた後にネットワークを切っても動きます。

関連ツール