2014-05-25 24 views
5

Ho un file CSV da 12 GB. Spero di estrarre solo alcune colonne da questi dati e quindi scrivere un nuovo CSV che spero di poter caricare in R per l'analisi.Utilizzo di Python per analizzare un CSV da 12 GB

Il problema è che viene visualizzato un errore di memoria quando si tenta di caricare l'intero elenco in una sola volta prima di scrivere il nuovo file CSV. Come posso analizzare i dati riga per riga e quindi creare un output CSV?

Ecco quello che ho finora:

import pandas 

colnames = ['contributor name', 'recipient name', 'recipient party', 'contributor cfscore', 'candidate cfscore', 'amount'] 

DATA = pandas.read_csv('pathname\filename.csv', names=colnames) 
DATA.to_csv(''pathname\filename.csv', cols = colnames) 
+1

Hanno hai guardato csvkit? Non ho idea di come sia in termini di efficienza o velocità. http://csvkit.readthedocs.org/en/0.7.3/ – A5C1D2H2I1M1N2O1R2T1

+0

Dove prendi quel file? – dawg

+0

Prova gli [Strumenti di Google CRUSH] (https://code.google.com/p/crush-tools/). Quel set di strumenti ha una vasta gamma di routine di manipolazione dei dati che dovrebbero consentire di tagliare, tagliare e persino fare alcune aggregazioni preliminari per ottenere i dati in una dimensione più gestibile. Inoltre, se è possibile ottenere i dati in un semplice database, 'dplyr' potrebbe essere una scelta eccellente per il crunch dei dati poiché molto probabilmente non mangerà tutta la memoria. – hrbrmstr

risposta

5

è possibile utilizzare il modulo csv per elaborare la linea linea per file. Qualcosa di simile potrebbe funzionare:

import csv 
infname = "csv.csv" 
outfname = "csv_stripped.csv" 
cols = ["col1", "col2", "col3"] 
with open(infname) as inf, open(outfname, 'w+') as outf: 
    reader = csv.DictReader(inf) 
    writer = csv.DictWriter(outf, cols, extrasaction='ignore') 
    writer.writeheader() 
    for line in reader: 
     writer.writerow(line) 

Per riferimento:

+0

@ user3342483 Probabilmente hai un errore da qualche parte (forse nomi di colonna o delimitatori?). Ho appena fatto un semplice test, funziona per me. – moooeeeep

+0

Spiacente, ho cancellato il mio ultimo commento per sbaglio. Penso che gli spazi nei miei nomi stanno buttando via le cose .... – StanO

+0

Sì, corretto i nomi delle colonne e funziona come un incantesimo! Grazie!!!! – StanO

-1

Prova questa:

file = open("csv.csv", "r") 
    for line in file: 
     print(line) 

non caricherà l'intero file in memoria, è l'analisi riga per riga.

+0

'per line in file' dovrebbe leggere una riga alla volta, senza caricarlo tutto in memoria – M4rtini

+0

Python carica il file quando si esegue' readlines() '. L'iterazione sul file ('per line in file: print (line)') non caricherà l'intero file in memoria e può infatti funzionare con flussi infiniti. –

+0

@AaronHall ha corretto il post, non si è reso conto che 'for line in lines 'non avrebbe effettivamente caricato l'intero file in memoria. – RydallCooper

7

In R, è possibile utilizzare la funzione fread dal popolare data.table package.

È possibile utilizzare l'argomento drop= per specificare le colonne da non leggere - non viene assegnata memoria per esse e non vengono letti affatto. O select= le colonne che vuoi conservare, se questo è più conveniente. fread può leggere molto, molto velocemente i file CSV.

Se si hanno a che fare con molti dati, probabilmente si vorrà familiarizzare con il pacchetto data.table.


In alternativa, ?read.csv.sql dal sqldf package dice che

Leggere un file in R filtrandola con un'istruzione SQL. Solo la parte filtrata viene elaborata da R, in modo che i file più grandi di R possano essere gestiti diversamente.

Ecco l'esempio:

write.csv(iris, "iris.csv", quote = FALSE, row.names = FALSE) 
iris2 <- read.csv.sql("iris.csv", 
         sql="select * from file where Species = 'setosa' ") 
+0

Grazie a GSee. Ho provato ad usare fread come hai descritto prima di postare questo, ma dopo circa 25 minuti circa, si otterrebbe un errore riguardo i separatori ... – StanO

+0

@ user3342483 forse [questo bug] (http://stackoverflow.com/questions/23833294/ data-tablefread-doesnt-like-missing-values-in-first-column) morde. :(Sarebbe fantastico se tu potessi eseguirlo di nuovo con 'verbose = TRUE' e inviare l'output all'elenco di datatable-help.Oppure se il file è disponibile online e potresti fornire un link, sarebbe utile eseguire il debug. – GSee

+0

Il file è disponibile a questo link, (attenzione, è un 2GB): https://dl.dropboxusercontent.com/u/2047562/contribDB_2012.zip L'errore R mi dà questo: Errore in fread (" ~/BonicaIdeology/contribDB_2012.csv ", verbose = T, select = c (" nome del contributore ",: Sep previsto (',') ma ' ' termina il campo 20 sulla riga 35265 durante la lettura dei dati: 2012," e: ind: 2012: 32748445 " , "15", 75, "2011-09-30", 4185397934, "arbitter, daniel ss", "arbitter", "daniel s", "s", "", "", "daniel ss", "I "," M "," 14871 lakewood dr "," plymouth "," MI ", 481702694," manager, core veh dyn – StanO

1

lettura di tutti i dati in memoria prima non è una buona idea.

Esistono due modi per gestire file di dati di grandi dimensioni.

  1. Flusso di ogni riga, selezionare le informazioni pertinenti e ignorare il resto fino a EOF. (vedi parser xml)

  2. Scambia ogni riga e scrivi l'intero dato in un formato molto migliore che ti consente di accedere facilmente alle informazioni pertinenti. Per esempio.pytables

1

Se si dispone di una funzione filter_row che restituiscono True quando si desidera mantenere la riga, è possibile utilizzare:

with open('input.csv') as inp: 
    with open('output.csv', 'w') as outp: 
     for line in inp: 
      if filter_row(line): 
       outp.write(line) 
2

Non hai bisogno di pitone o i pacchetti R in più per fare questo . È possibile utilizzare l'argomento colClasses con l'input di dati in R per leggere solo in determinate colonne. Assegna a una colonna il valore colClasses di "NULL" per impedire che venga caricato durante l'immissione.

Esempio per un file ("myfile.csv") con 3 colonne, se il primo devono essere trattati come character, il terzo devono essere trattati come integer, e il secondo dovrebbe essere omesso:

read.csv("myfile.csv", colClasses=c("character", "NULL", "integer")) 

Questo metodo richiede però di specificare le classi per ogni colonna del file.

Potrebbe anche essere la pena di voi leggendo i consigli per l'utilizzo della memoria in http://stat.ethz.ch/R-manual/R-devel/library/utils/html/read.table.html se si dispone di molte righe.

+0

Tecnicamente questo può funzionare, ma le prestazioni di read.csv su un file da 12 GB saranno sicuramente un problema. –

+0

Vero, questo sarebbe più veloce della lettura dell'intero file senza "NULL", ma ancora piuttosto lento. – ping

0

È possibile ottenere ciò utilizzando R e JDBC. Creiamo un file CSV di esempio.

write.table(x=mtcars, file="mtcars.csv", sep=",", row.names=F, col.names=T) # create example csv file 

scaricare e salvare il il driver JDBC CSV da questo link: http://sourceforge.net/projects/csvjdbc/files/latest/download e quindi l'installazione del driver.

> library(RJDBC) 

> path.to.jdbc.driver <- "jdbc//csvjdbc-1.0-18.jar" 
> drv <- JDBC("org.relique.jdbc.csv.CsvDriver", path.to.jdbc.driver) 
> conn <- dbConnect(drv, sprintf("jdbc:relique:csv:%s", getwd())) # replace getwd() with location of csv file 

ora è possibile comporre una query e selezionare le colonne avete bisogno e, se necessario, aggiungere una clausola WHERE per filtrare sui dati per selezionare solo le righe in cui ingranaggi assume il valore 5:

> dbGetQuery(conn, "select mpg, cyl, gear from mtcars where gear = '5'") 
    mpg cyl gear 
1 26 4 5 
2 30.4 4 5 
3 15.8 8 5 
4 19.7 6 5 
5 15 8 5 
Problemi correlati