2016-07-19 111 views
6

Sto lavorando con grandi matrici di dati (Nrow x Ncol) che sono troppo grandi per essere memorizzate. Invece, è normale nel mio campo di lavoro salvare i dati in un file binario. A causa della natura del lavoro, ho solo bisogno di accedere a 1 colonna della matrice alla volta. Devo anche essere in grado di modificare una colonna e quindi salvare la colonna aggiornata nel file binario. Finora sono riuscito a capire come salvare una matrice come file binario e come leggere 1 'colonna' della matrice dal file binario in memoria. Tuttavia, dopo aver modificato il contenuto di una colonna non riesco a capire come salvare quella colonna nel file binario.Julia: Come modificare una colonna di una matrice che è stata salvata come file binario?

Come esempio, si supponga che il file di dati sia una matrice di identità a 32 bit che è stata salvata sul disco.

Nrow = 500 
Ncol = 325 
data = eye(Float32,Nrow,Ncol) 
stream_data = open("data","w") 
write(stream_data,data[:]) 
close(stream_data) 

Leggere l'intero file dal disco e poi rimodellare indietro nella matrice è semplice:

stream_data = open("data","r") 
data_matrix = read(stream_data,Float32,Nrow*Ncol) 
data_matrix = reshape(data_matrix,Nrow,Ncol) 
close(stream_data) 

Come già detto, i dati-matrici sto lavorando sono troppo grandi per leggere nella memoria e di conseguenza il codice scritto sopra normalmente non sarebbe possibile eseguirlo. Invece, ho bisogno di lavorare con 1 colonna alla volta. La seguente è una soluzione per leggere 1 colonna (ad esempio la colonna 7) della matrice in memoria:

icol = 7 
stream_data = open("data","r") 
position_data = 4*Nrow*(icol-1) 
seek(stream_data,position_data) 
data_col = read(stream_data,Float32,Nrow) 
close(stream_data) 

Notare che il coefficiente '4' nella variabile 'position_data' è perché sto lavorando con Float32. Inoltre, non capisco appieno ciò che la cercano comando sta facendo qui, ma mi sembra essere dare l'output corretto in base alle seguenti prove:

data == data_matrix  # true 
data[:,7] == data_col # true 

Per il bene di questo problema, consente di dire che ho ha stabilito che la colonna ho caricato (cioè la colonna 7) deve essere sostituito con gli zeri:

data_col = zeros(Float32,size(data_col)) 

il problema ora, è quello di capire come salvare questa colonna indietro nel file binario senza influenzare uno qualsiasi degli altri dati. Ovviamente intendo usare "scrivi" per eseguire questo compito. Tuttavia, non sono del tutto sicuro su come procedere. So che ho bisogno di iniziare aprendo un flusso ai dati; tuttavia non sono sicuro di quale "modalità" devo usare: "w", "w +", "a" o "a +"? Ecco un tentativo fallito con "w":

icol = 7 
stream_data = open("data","w") 
position_data = 4*Nrow*(icol-1) 
seek(stream_data,position_data) 
write(stream_data,data_col) 
close(stream_data) 

Il file binario originale (prima del mio tentativo fallito di modificare il file binario) occupata 650000 byte su disco. Ciò è coerente con il fatto che la matrice è di dimensioni 500x325 e i numeri di Float32 occupano 4 byte (vale a dire 4 * 500 * 325 = 650000). Tuttavia, dopo il mio tentativo di modificare il file binario, ho osservato che il file binario occupa ora solo 14000 byte di spazio. Alcuni dati matematici veloci mostrano che 14000 byte corrispondono a 7 colonne di dati (4 * 500 * 7 = 14000). Un controllo rapido conferma che il file binario ha sostituito tutti i dati originali con una nuova matrice con dimensione 500x7 e i cui elementi sono tutti zeri.

stream_data = open("data","r") 
data_new_matrix = read(stream_data,Float32,Nrow*7) 
data_new_matrix = reshape(data_new_matrix,Nrow,7) 
sum(abs(data_new_matrix)) # 0.0f0 

Cosa devo fare/modificare per modificare solo la settima 'colonna' nel file binario?

+0

sono [questi] (http://docs.julialang.org/en/release-0.4/stdlib/io-network/#memory-mapped-i-o) qualsiasi uso qui? – daycaster

+0

Forse cambia 'stream_data = open (" data "," w ")' a 'stream_data = open (" data "," w + ")' nell'aggiornamento vettoriale. Notare il 'w +'. La documentazione pertinente è http://docs.julialang.org/en/release-0.4/stdlib/io-network/#Base.open –

+0

[SharedArrays] (http://docs.julialang.org/en/release-0.4 /stdlib/parallel/#Base.SharedArray) farà tutto ciò che hai appena specificato per te. Utilizzare il costruttore con nome file –

risposta

1

Invece di

icol = 7 
stream_data = open("data","w") 
position_data = 4*Nrow*(icol-1) 
seek(stream_data,position_data) 
write(stream_data,data_col) 
close(stream_data) 

nel PO, scrivere

icol = 7 
stream_data = open("data","r+") 
position_data = 4*Nrow*(icol-1) 
seek(stream_data,position_data) 
write(stream_data,data_col) 
close(stream_data) 

cioè sostituire "w" con "r+" e tutto funziona.

Il riferimento a open è http://docs.julialang.org/en/release-0.4/stdlib/io-network/#Base.open e spiega le varie modalità. Preferibilmente, non utilizzare open con il parametro stringa originale un po 'confuso ma decisamente più lento.

+1

Questo sembra fare esattamente quello che volevo. E solo per essere sicuro di capire cosa stai dicendo riguardo al parametro stringa, stai dicendo che sarà più veloce usare 'stream_data = open (" data ", true, true, false, false, false)' piuttosto che 'stream_data = open ("data", "r +") 'per scrivere nuovamente la colonna nel file binario? (e qualcosa di simile per la lettura della colonna in memoria) – Landon

1

È possibile utilizzare SharedArrays per la necessità di descrivere:

data=SharedArray("/some/absolute/path/to/a/file", Float32,(Nrow,Ncols)) 
# do something with data 
data[:,1]=a[:,1].+1 
exit() 

# restart julia 
data=SharedArray("/some/absolute/path/to/a/file", Float32,(Nrow,Ncols)) 
@show data[1,1] 
# prints 1 

Ora, essere consapevoli che si suppone di gestire la sincronizzazione di lettura/scrittura da/a questo file (se si dispone di lavoratori async) e che non dovresti cambiare la dimensione dell'array (a meno che tu non sappia cosa stai facendo).

+0

Sembra che farà il trucco. Quando carichi i dati come SharedArray, carica anche i dati in memoria o funziona completamente fuori dal disco? Se funziona completamente su disco, ho ragione a pensare che sarebbe più veloce estrarre la colonna corrente in una nuova variabile in modo che io possa lavorarci sopra in memoria? – Landon

+0

Non sono riuscito a trovare alcuna documentazione per rispondere alle vostre domande. D'altra parte, vista la filosofia che sta dietro a Julia, basta provarlo e profilare/ottimizzare successivamente di conseguenza –