2014-07-11 14 views
5

Sto salvando un array sparse numpy (densificato) in un csv. Il risultato è che ho un csv da 3 GB. Il problema è che il 95% delle celle è 0.0000. Ho usato fmt='%5.4f'. Come posso formattare e salvare in modo tale che gli zeri vengano salvati solo come 0 e i float non nulli vengano salvati con il formato '%5.4f'? Sono sicuro di poter portare il 3GB a 300 MB se riesco a farlo.Come formattare in numpy savetxt tale che gli zeri vengano salvati solo come "0"

Sto usando

np.savetxt('foo.csv', arrayDense, fmt='%5.4f', delimiter = ',') 

Grazie saluti

+0

L'utilizzo di un formato di archiviazione diverso e non denso potrebbe produrre risultati migliori. Vedi http://stackoverflow.com/questions/8955448/save-load-scipy-sparse-csr-matrix-in-portable-data-format per come farlo. – user2357112

+0

Inoltre, considera di comprimerlo. 'savetxt' e' loadtxt' usano automaticamente gzip se il nome del file termina in '.gz'; questo potrebbe essere un modo semplice per ridurre il tuo file. – user2357112

risposta

6

Se si guarda il codice sorgente di np.savetxt, vedrete che, mentre c'è un bel po 'di codice per gestire gli argomenti e le differenze tra Python 2 e Python 3, è in definitiva un semplice pitone loop sulle righe, in cui ogni riga è formattata e scritta nel file. Quindi non perderai nessuna esibizione se scrivi la tua. Ad esempio, ecco una funzione abita in fondo che scrive zeri compatti:

def savetxt_compact(fname, x, fmt="%.6g", delimiter=','): 
    with open(fname, 'w') as fh: 
     for row in x: 
      line = delimiter.join("0" if value == 0 else fmt % value for value in row) 
      fh.write(line + '\n') 

Ad esempio:

In [70]: x 
Out[70]: 
array([[ 0.  , 0.  , 0.  , 0.  , 1.2345 ], 
     [ 0.  , 9.87654321, 0.  , 0.  , 0.  ], 
     [ 0.  , 3.14159265, 0.  , 0.  , 0.  ], 
     [ 0.  , 0.  , 0.  , 0.  , 0.  ], 
     [ 0.  , 0.  , 0.  , 0.  , 0.  ], 
     [ 0.  , 0.  , 0.  , 0.  , 0.  ]]) 

In [71]: savetxt_compact('foo.csv', x, fmt='%.4f') 

In [72]: !cat foo.csv 
0,0,0,0,1.2345 
0,9.8765,0,0,0 
0,3.1416,0,0,0 
0,0,0,0,0 
0,0,0,0,0 
0,0,0,0,0 

allora, fino a quando si sta scrivendo la propria funzione savetxt, si potrebbe anche fare maneggia matrici sparse, quindi non devi convertirlo in un array numerico (denso) prima di salvarlo. (Suppongo che l'array sparse sia implementato utilizzando una delle rappresentazioni sparse da scipy.sparse.) Nella seguente funzione, l'unica modifica è da ... for value in row a ... for value in row.A[0].

def savetxt_sparse_compact(fname, x, fmt="%.6g", delimiter=','): 
    with open(fname, 'w') as fh: 
     for row in x: 
      line = delimiter.join("0" if value == 0 else fmt % value for value in row.A[0]) 
      fh.write(line + '\n') 

Esempio:

In [112]: a 
Out[112]: 
<6x5 sparse matrix of type '<type 'numpy.float64'>' 
    with 3 stored elements in Compressed Sparse Row format> 

In [113]: a.A 
Out[113]: 
array([[ 0.  , 0.  , 0.  , 0.  , 1.2345 ], 
     [ 0.  , 9.87654321, 0.  , 0.  , 0.  ], 
     [ 0.  , 3.14159265, 0.  , 0.  , 0.  ], 
     [ 0.  , 0.  , 0.  , 0.  , 0.  ], 
     [ 0.  , 0.  , 0.  , 0.  , 0.  ], 
     [ 0.  , 0.  , 0.  , 0.  , 0.  ]]) 

In [114]: savetxt_sparse_compact('foo.csv', a, fmt='%.4f') 

In [115]: !cat foo.csv 
0,0,0,0,1.2345 
0,9.8765,0,0,0 
0,3.1416,0,0,0 
0,0,0,0,0 
0,0,0,0,0 
0,0,0,0,0 
+0

Grazie mille Warren. Questo funzionerà sicuramente. La mia matrice sparsa era il risultato di una trasformazione su un modello di TfidfVectorizer. Esso restituisce un float64 doppia dimensione matrice sparsa come qui di seguito (per esempio sto considerando 10 termini migliori) \ n' (0, 9) \t 0,434529124115 (0, 8) \t 0,506103404485 (0, 6) \t 0,342163203439 (0, 5) \t 0,114195114018 (0, 4) \t 0,228240906166 (0, 0) \t 0,506863556372 (1, 9) \t 0,179650406184 (1, 8) \t 0,650974675792 (1, 5) \t 0,385568606136 (1, 3) \t 0.0601214405201 (1, 2) \t 0.117613972075 (1, 1) \t 0.34801600856 (1, 0) \t 0.27164684163 ... '. Btw the 0.4g fmt funziona anche da solo. – Run2

2

Sarebbe molto meglio se si è salvato solo le voci non-zeri nella tua matrice sparse (m nell'esempio qui sotto), si potrebbe ottenere che facendo:

fname = 'row_col_data.txt' 
m = m.tocoo() 
a = np.vstack((m.row, m.col, m.data)).T 
header = '{0}, {1}'.format(*m.shape) 
np.savetxt(fname, a, header=header, fmt=('%d', '%d', '%5.4f')) 

e la matrice sparsa possono essere ricomposti fare:

+0

Ciao Castro - grazie per questa risposta. Ho imparato molto da questo. Ma, il fatto è che ho bisogno del formato di colonne delle righe (n, m) in csv e di tutte le colonne m. Questo perché ho bisogno di caricarlo in WEKA e SMOTE. Il tuo approccio è la creazione di un formato xls, in (n1,2) righe colonne e manca anche i valori 0. – Run2

+0

CT Zhu aveva risposto correttamente - ma per qualche motivo il post è stato cancellato. Non posso sceglierlo come risposta corretta. Solo usando 'fmt = '%. 4g'' durante il salvataggio è stato risolto. Aggiungerò una risposta se CT Zhu non aggiungerà di nuovo quel post in alcuni giorni. – Run2

+0

@ Run2 i valori '0' non sono mancanti, il fatto è che non sono memorizzati in una matrice sparsa, questo è lo scopo principale di usare questo tipo di matrice quindi credo che non ti debba preoccupare con' 0' valori ... se hai bisogno di un array denso puoi fare 'm.toarray()', dove puoi vedere gli zeri ... –

4

Un altro semplice opzione che può funzionare dato le vostre esigenze è la 'g' identificatore. Se ti preoccupi di più delle cifre significative e meno di vedere esattamente il numero x di cifre e non ti dispiace passare da scientifico a float, questo è il trucco. Per esempio:

np.savetxt("foo.csv", arrayDense, fmt='%5.4g', delimiter=',') 

Se arrayDense è questo:

matrix([[ -5.54900000e-01, 0.00000000e+00, 0.00000000e+00], 
    [ 0.00000000e+00, 3.43560000e-08, 0.00000000e+00], 
    [ 0.00000000e+00, 0.00000000e+00, 3.43422000e+01]]) 

Il tuo modo sarebbe resa:

-0.5549,0.0000,0.0000 
0.0000,0.0000,0.0000 
0.0000,0.0000,34.3422 

È possibile che questo produrrebbe invece:

-0.5549, 0, 0 
0,3.436e-08, 0 
0, 0,34.34 

In questo modo è anche più flessibile. Si noti che utilizzando 'g' invece di 'f', non si perdono dati (ad esempio 3.4356e-08 anziché 0.0000). Questo ovviamente dipende da cosa si imposta la precisione a comunque.

Problemi correlati