2012-08-22 44 views
10

非常に大きなnetCDFファイル(それぞれ〜400Gb)のデータを処理しようとしています。各ファイルにはいくつかの変数があり、システムメモリ(例:180Gbと32Gb RAM)よりもはるかに大きいものです。私はnumpyとnetCDF4-pythonを使用しようとしていますが、スライスを一度にコピーしてそのスライスを操作することによって、これらの変数に対していくつかの操作を行います。残念ながら、各スライスを読み取るだけで実際にはかなり長い時間がかかり、パフォーマンスが低下します。非常に大きなnetCDFファイルをPythonで扱う

たとえば、変数の1つは形状(500, 500, 450, 300)の配列です。私は、スライス[:,:,0]上で操作したいので、私は次の操作を行います。

import netCDF4 as nc 

f = nc.Dataset('myfile.ncdf','r+') 
myvar = f.variables['myvar'] 
myslice = myvar[:,:,0] 

しかし、最後のステップは、(私のシステムで約5分)本当に長い時間がかかります。たとえば、図形(500, 500, 300)の変数をnetcdfファイルに保存した場合、同じサイズの読み取り操作には数秒しかかかりません。

私はこれをスピードアップできる方法はありますか?明白な道は、私が選択しているインデックスが最初に現れるように配列を転置することです。しかし、このような大きなファイルでは、これはメモリ上で行うことは不可能であり、簡単な操作にはすでに長い時間がかかることを考えると、それを試みるのがさらに遅くなっているように見えます。私が望むのは、Fortranのインターフェースget_vara関数のように、netcdfファイルのスライスを素早く読み取る方法です。または配列を効率的に転置する何らかの方法。

+1

あなたはそれを転置よりもデータをよりやりたい場合は、[ 'xarray'](http://xarray.pydata.org/en/stable/)モジュールを見て:それは非常に素晴らしいを提供します['dask'](http://dask.pydata.org/en/latest/)のメモリ不足配列へのインタフェースです。 – j08lue

答えて

7

あなたがここに文書化されてnccopyユーティリティを使用してメモリに収まるには大きすぎるのnetCDF変数を移調することができます

http://www.unidata.ucar.edu/netcdf/docs/guide_nccopy.html

アイデアは「rechunk」チャンクの何形状を指定してファイルにあります(多次元タイル) を使用してください。どのくらいの量のメモリをバッファとして使用するかを指定することができます。 をチャンクキャッシュに使用する方法を指定できますが、これらの使用方法間でメモリを最適に使用する方法が明確ではないため、 はいくつかの例を試して時間を計る必要があります。完全に変数を移調するのではなく、 あなたはおそらく に沿ってあなたのスライスの2つの大きな寸法を多くのデータを持っており、他の次元に沿ってわずか数の値を持つチャンクを指定することで、それを「部分的に移調」にしたいです。

+0

お返事ありがとうございます。私はチャンクを大いに見ていないので、とても面白かったです。私は次元(500,500,300,400)を持つ変数があると仮定します。私が3次元で1のチャンクを行う場合、これは、その軸が最も速い(すなわち、連続した)部分的な転置を行うことに類似していますか?私は軸でチャンクを変更しましたが、私はもっと読むつもりでしたが、3Dスライスを取得するのにまだまだ時間がかかります。これがファイルシステム/ネットワークの問題かどうかを調査します。 – tiago

+0

いいえ、3次元のチャンク長を1にすると、その次元に沿って読み取るときに4バイトの値ごとに400 MBのチャンクにアクセスするため、その次元が最も遅くなります。しかし、各ディメンション(各チャンクは50x40x30x40)に沿って10チャンクを使用すると、各チャンクは約12MB(値あたり4バイトと仮定します)を構成し、任意のディメンションに沿った値の "シリンダ" 50x50x30x40チャンク)。いくつかの方向でアクセス時間を改善する方法の例については、2つのスライドを参照してください。http://www.unidata.ucar.edu/netcdf/workshops/2011/chunk_cache/Problem.html –

+0

上記のコメントへの修正: (50x50x30x40のチャンク)」と「(50x50x30x40のチャンク)」... –

3

これはコメントであり、回答ではありませんが、私は上記にはコメントできません。申し訳ありません。

myvar[:,:,i]を処理して、irange(450)とします。その場合は、あなたのような何かやろうとしている。

for i in range(450): 
    myslice = myvar[:,:,i] 
    do_something(slice) 

をし、ボトルネックはmyslice = myvar[:,:,i]にアクセスしています。あなたはmoreslices = myvar[:,:,0:n]にアクセスするのにかかる時間を比較しようとしましたか?それはデータの連続性であり、おそらくそれで時間を節約することができます。あなたのメモリが提供するものと同じ大きさのnを選択し、次にデータの次のチャンクmoreslices = myvar[:,:,n:2n]などを処理します。

+0

ありがとうございます。私は 'myvar [:、:、0:n]にアクセスするのと比べて、' myvar [:、:、0] 'とほぼ同じ時間がかかる。だから、これは少なくとも一つの方法ですが、私はまだそのようなペナルティがなぜ始まるのかを調べようとしています。 'myvar [:、:、0:n]'は連続していないことに注意してください。 – tiago

+0

まあ、 'myvar [1,0,0]'が 'myvar [2,0,0]'と連続していないのは事実です。しかし、 'myvar [i、i、0]'は 'myvar [i、i、1]'と実際に連続しているので、ほぼ同じ時間がかかります。それは今より意味があるのですか? – gg349

関連する問題