2014-01-05 10 views
20

Ich arbeite mit einer Reihe großer numpy Arrays, und als diese in letzter Zeit zu viel Speicher zu kauen begannen, wollte ich sie durch numpy.memmap Instanzen ersetzen. Das Problem ist, dass ich ab und zu die Größe der Arrays ändern muss, und ich würde das am besten tun. Dies funktionierte recht gut mit gewöhnlichen Arrays, aber wenn man versucht, auf memaps zu meckern, werden die Daten möglicherweise geteilt, und selbst das Deaktivieren der Refecks hilft nicht.Größenanpassung von numpy.memmap Arrays

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 

Größenanpassung der zugrunde liegenden mmap-Puffer funktioniert einwandfrei. Das Problem besteht darin, wie diese Änderungen am Array-Objekt widergespiegelt werden. Ich habe diese workaround gesehen, aber leider wird die Größe des Arrays nicht geändert. Es gibt auch einige numpy documentation über die Größenänderung von mmaps, aber es funktioniert eindeutig nicht, zumindest mit der Version 1.8.0. Irgendwelche anderen Ideen, wie man die eingebauten Größenänderungskontrollen überschreibt?

+0

Ich fühle mich wie ich etwas ... dieser Code läuft gut für mich nicht fehlen darf. Läuft es für dich? Wollen Sie das nicht tun? http://codepad.org/eEWmYBHZ –

+0

@ three_pineapples Er möchte die Gesamtgröße des Arrays ändern - Ihr Code ändert es einfach –

+0

@ali_m Ah, ich verstehe. Ich habe das von der Frage nicht verstanden, aber wie gesagt, ich dachte, ich hätte etwas übersehen! Danke für die Klärung –

Antwort

10

Das Problem ist, dass das Flag OWNDATA False ist, wenn Sie Ihr Array erstellen. Sie können, dass durch die Flagge ändern erfordern um wahr zu sein, wenn Sie das Array erstellen:

>>> 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,) 

Der einzige Nachteil ist, dass es das Array erstellen kann und eine Kopie zu sein, sicherzustellen, dass die Anforderungen erfüllt sind.

bearbeiten Spar Adresse:

Wenn Sie die Größe neu Array auf der Festplatte speichern möchten, können Sie die memmap als .npy formatierte Datei und öffnen als numpy.memmap sparen, wenn Sie re- müssen öffnen und die Verwendung als 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]) 

bearbeiten eine andere Methode bieten:

Sie erhalten schließen können, was Sie suchen durch re-Sizing die Basis mmap (a.base oder a._mmap, in uint8 Format gespeichert) und „Nachladen“ der 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

Interessant. Leider sieht es für mich so aus, als ob es immer eine Kopie im Speicher erstellt. Wenn ich versuche, in das Array zu schreiben, das Array zu löschen, zu löschen und wieder zu öffnen, ist es wie zuvor leer.Also ich denke die Daten werden nie wirklich auf die Platte geschrieben. – Michael

+0

Ich habe ein Beispiel hinzugefügt, wie Sie es speichern und später als memmap wieder öffnen können. – wwwslinger

+0

@wwwslinger Das Problem mit Ihrer Antwort ist, dass, wenn 'a' zu groß ist, um in den Kernspeicher zu passen (warum sonst würden Sie einen Speicher verwenden) mapped array?), und dann eine weitere Kopie davon im Kern zu erstellen, wird offensichtlich einige Probleme verursachen. Es wäre besser, wenn Sie ein neues Speichermapping-Array mit der korrekten Größe von Grund auf erstellen und es dann in Blöcke mit dem Inhalt von "a" füllen. –

3

Wenn mich nicht alles täuscht, erreicht dies im Wesentlichen, was @ wwwslinger zweite Lösung der Fall ist, aber ohne dass sie manuell die Größe des neuen memmap in Bits angegeben werden: für die

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]) 

diese gut funktioniert, wenn das neue Array als die alten größer sein muss, aber ich glaube nicht, diese Art von Ansatz erlaubt Größe der speicherabgebildeten Datei, die automatisch abgeschnitten wird, wenn das neue Array kleiner ist.

Manuell Größe der Basis ändern, wie in @ wwwslingers Antwort, scheint die Datei abgeschnitten werden, aber es reduziert nicht die Größe des Arrays.

Zum Beispiel:

# 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

Dies ist ein ähnlicher Ansatz wie der in der von mir geposteten Problemumgehung. Ich würde eine Inplace-Lösung bevorzugen, da es mich davor bewahren würde, das Objekt noch weiter zu kapseln. Wie auch immer, das ist wahrscheinlich das, womit ich am Ende leben muss. – Michael

+0

@Michael Wenn Sie dies noch nicht getan haben, sollten Sie dieses Problem wahrscheinlich den numpy Maintainern melden. Zumindest sollte der Docstring für die 'np.memmap'-Klasse aktualisiert werden, um die Tatsache widerzuspiegeln, dass es derzeit nicht möglich ist, Speicher-Mapped-Arrays an Ort und Stelle zu resizen. –

+0

habe ich nicht, aber wie es aussieht, gibt es keine einfache Lösung für das, ich werde. – Michael