2014-01-05 31 views
20

私は大量の大量の配列を扱っています。最近、あまりにも多くのメモリを噛んでしまいましたので、それらをnumpy.memmapインスタンスに置き換えたかったのです。問題は、今、私は配列のサイズを変更する必要があり、私はその場所で行うことをお勧めします。これは普通の配列ではうまくいきましたが、memmapsでこれを試してみると、データが共有され、refcheckを無効にしても役立たないという不満があります。numpy.memmapの配列のサイズ変更

a = np.arange(10) 
a.resize(20) 
a 
>>> array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 

a = np.memmap('bla.bin', dtype=int) 
a 
>>> memmap([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 

a.resize(20, refcheck=False) 
--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-41-f1546111a7a1> in <module>() 
----> 1 a.resize(20, refcheck=False) 

ValueError: cannot resize this array: it does not own its data 

下位のmmapバッファのサイズを変更すると、問題なく動作します。問題は、これらの変更を配列オブジェクトに反映させる方法です。私はこのworkaroundを見たことがありますが、残念ながら、配列の位置は変更されません。 mmapのサイズ変更についてはnumpy documentationもありますが、少なくともバージョン1.8.0では明らかに動作しません。他のアイデア、どのようにinbuiltのサイズ変更チェックをオーバーライドするには?

+0

私は何かが欠けする必要がありますように...このコードは私のために正常に実行さを感じます。それはあなたのために実行されますか?これはあなたがしたいことではありませんか? http://codepad.org/eEWmYBHZ –

+0

@three_pineapples彼は配列の合計サイズを変更したい - あなたのコードはちょうどそれを再構成する –

+0

@ali_mああ、私は参照してください。私は質問からそれを得ませんでしたが、私が言ったように、私は何かが欠けていると思った! –

答えて

10

問題は、アレイを作成するときにフラグOWNDATAがFalseであることです。

>>> a = np.require(np.memmap('bla.bin', dtype=int), requirements=['O']) 
>>> a.shape 
(10,) 
>>> a.flags 
    C_CONTIGUOUS : True 
    F_CONTIGUOUS : True 
    OWNDATA : True 
    WRITEABLE : True 
    ALIGNED : True 
    UPDATEIFCOPY : False 
>>> a.resize(20, refcheck=False) 
>>> a.shape 
(20,) 

唯一の注意点は、それが配列を作成し、要件が満たされていることを確認しコピーを作成することです:あなたは、配列を作成するときに真であるとのフラグを必要とすることによってすることを変更することができます。

編集省対処する:

を使用すると、ディスクに再サイズの配列を保存したい場合は、あなたが再する必要があるときnumpy.memmapとして、ファイルのオープンをフォーマットし.npyとしてmemmapを保存することができますそれを開くとmemmapとして使用します。

>>> a[9] = 1 
>>> np.save('bla.npy',a) 
>>> b = np.lib.format.open_memmap('bla.npy', dtype=int, mode='r+') 
>>> b 
memmap([0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 

編集、別の方法を提供する:

をあなたが再サイズで探しているものに近いかもしれませんベース(uint8の形式で保存されa.baseまたはa._mmap、)MMAPとmemmapを「リロード」:

>>> a = np.memmap('bla.bin', dtype=int) 
>>> a 
memmap([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 
>>> a[3] = 7 
>>> a 
memmap([0, 0, 0, 7, 0, 0, 0, 0, 0, 0]) 
>>> a.flush() 
>>> a = np.memmap('bla.bin', dtype=int) 
>>> a 
memmap([0, 0, 0, 7, 0, 0, 0, 0, 0, 0]) 
>>> a.base.resize(20*8) 
>>> a.flush() 
>>> a = np.memmap('bla.bin', dtype=int) 
>>> a 
memmap([0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 
+2

面白いです。残念ながら、私にとっては常にメモリにコピーを作成するようです。配列への書き込み、フラッシング、削除、および再オープンを試みると、前と同じように再び空になります。だから、データは実際にディスクに書き込まれることはないと思います。 – Michael

+0

これを保存して後でmemmapとして再オープンする方法の例を追加しました – wwwslinger

+0

@wwwslinger答えに問題があるのは、 'a'が大きすぎてコアメモリに収まらない場合です(そうでなければ、マップされた配列?)、それからコアに別のコピーを作成することは明らかにいくつかの問題を引き起こすでしょう。正しいサイズのメモリマップされた新しい配列を最初から作り、 'a'の内容をチャンクで埋めておく方がよいでしょう。 –

3

私は間違っていない場合は、これは@ wwwslingerの第二の溶液が何をするのか、基本的に実現し、しかしなし手動ビットで新しいmemmapのサイズを指定する必要が:

In [1]: a = np.memmap('bla.bin', mode='w+', dtype=int, shape=(10,)) 

In [2]: a[3] = 7 

In [3]: a 
Out[3]: memmap([0, 0, 0, 7, 0, 0, 0, 0, 0, 0]) 

In [4]: a.flush() 

# this will append to the original file as much as is necessary to satisfy 
# the new shape requirement, given the specified dtype 
In [5]: new_a = np.memmap('bla.bin', mode='r+', dtype=int, shape=(20,)) 

In [6]: new_a 
Out[6]: memmap([0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 

In [7]: a[-1] = 10 

In [8]: a 
Out[8]: memmap([ 0, 0, 0, 7, 0, 0, 0, 0, 0, 10]) 

In [9]: a.flush() 

In [11]: new_a 
Out[11]: 
memmap([ 0, 0, 0, 7, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0]) 

新しい配列が古いものよりも大きくする必要があるときにこれはうまく動作しますが、私はこのタイプのアプローチがが可能になるとは思いません新しい配列が小さければ自動的に切り捨てられるメモリマップされたファイルのサイズ。

@ wwwslingerの回答のように、ベースのサイズを手動で変更すると、ファイルを切り捨てることができますが、配列のサイズは縮小されません。例えば

# this creates a memory mapped file of 10 * 8 = 80 bytes 
In [1]: a = np.memmap('bla.bin', mode='w+', dtype=int, shape=(10,)) 

In [2]: a[:] = range(1, 11) 

In [3]: a.flush() 

In [4]: a 
Out[4]: memmap([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 

# now truncate the file to 40 bytes 
In [5]: a.base.resize(5*8) 

In [6]: a.flush() 

# the array still has the same shape, but the truncated part is all zeros 
In [7]: a 
Out[7]: memmap([1, 2, 3, 4, 5, 0, 0, 0, 0, 0]) 

In [8]: b = np.memmap('bla.bin', mode='r+', dtype=int, shape=(5,)) 

# you still need to create a new np.memmap to change the size of the array 
In [9]: b 
Out[9]: memmap([1, 2, 3, 4, 5]) 
+0

これは私が投稿した回避策のような同様のアプローチです。私はインプレース・ソリューションを好みます。オブジェクトをさらにカプセル化する手間が省けます。とにかく、これはおそらく私が最後に一緒に生きなければならないものです。 – Michael

+0

@Michaelあなたがまだ持っていないのなら、おそらくこの問題をnumpyのメンテナーに報告してください。少なくとも、np.memmapクラスのdocstringは、現在メモリマップされた配列の位置を変更することが現在できないという事実を反映するように更新されるべきです。 –

+0

私は持っていませんが、これには簡単な解決策がないように見えます。 – Michael

関連する問題