2013-03-20 8 views
16

Il titolo è piuttosto auto-esplicativo qui, ma elaborerò come segue. Alcune delle mie attuali tecniche per attaccare questo problema si basano sulle soluzioni presentate nella domanda this. Tuttavia, sto affrontando diverse sfide e vincoli quindi mi chiedevo se qualcuno potesse tentare di prendere una pugnalata a questo problema. Sto cercando di capire il problema usando il pacchetto bigmemory ma ho incontrato delle difficoltà.Lettura di 40 GB di file csv in R utilizzando bigmemory

vincoli presenti:

  • utilizzando un server Linux con 16 GB di RAM
  • Dimensioni di 40 GB CSV
  • No di righe: 67.194.126.114

sfide

  • È necessario essere in grado di campionare casualmente dataset più piccoli (5-10 milioni di righe) da una big.matrix o una struttura di dati equivalente.
  • È necessario essere in grado di rimuovere qualsiasi riga con una singola istanza di NULL mentre si analizza in una big.matrix o in una struttura di dati equivalente.

Finora, i risultati non sono positivi. Evidentemente, sto fallendo in qualcosa o forse, semplicemente non capisco lo bigmemory documentation abbastanza bene. Quindi, ho pensato di chiedere qui per vedere se qualcuno ha usato

Qualche consiglio, consiglio su questa linea di attacco ecc.? O dovrei passare a qualcos'altro? Mi scuso se questa domanda è molto simile alla precedente, ma ho pensato che la scala dei dati era circa 20 volte più grande delle domande precedenti. Grazie !

+1

Come su un campione del contenuto del file? –

+0

Dove esattamente stai fallendo? Che tipo di dati ci sono nel file .csv - è tutto 'double's,' int's o altrimenti? Come sono rappresentate le voci 'NULL' nel file? Ci sono nomi di righe/colonne? E cosa hai provato? Dato un .csv di struttura appropriata, 'read.big.matrix' dovrebbe portarti lì. –

+0

Ulteriori informazioni sarebbero buone, ma perché non importarle in SQL, fare qualche preparazione lì e poi caricarle in R? –

risposta

18

Non so su bigmemory, ma per soddisfare le vostre sfide non è necessario leggere il file. Semplicemente pipe un po 'di bash/awk/sed/python/qualsiasi elaborazione per fare i passi che vuoi, cioè lanciare linee NULL e selezionare a caso le righe N e leggerlo.

Ecco un esempio di utilizzo di awk (presupponendo di volere 100 righe casuali da un file che ha linee 1M).

read.csv(pipe('awk -F, \'BEGIN{srand(); m = 100; length = 1000000;} 
         !/NULL/{if (rand() < m/(length - NR + 1)) { 
           print; m--; 
           if (m == 0) exit; 
           }}\' filename' 
     )) -> df 

non era ovvio per me cosa intende per NULL, quindi ho usato la comprensione letterale di esso, ma dovrebbe essere facile modificarlo per soddisfare le vostre esigenze.

+1

Questa è in realtà una buona risposta e ho risolto il problema una volta tornato implementando una soluzione molto simile. Grazie per questa risposta. Lo accetterò – Shion

11

Questa è una soluzione R pura per la sfida del campionamento da un file di testo di grandi dimensioni; ha il merito aggiuntivo di disegnare un campione casuale di esattamente n. Non è troppo inefficiente, sebbene le linee siano analizzate ai vettori di caratteri e questo è relativamente lento.

Iniziamo con una firma di funzione, dove forniamo un nome di file, la dimensione del campione che vogliamo disegnare, un seme per il generatore di numeri casuali (in modo che possiamo riprodurre il nostro campione casuale!), L'indicazione se c'è una riga di intestazione, e poi una funzione di "lettore" che useremo per analizzare il campione in un oggetto visto da R che include argomenti aggiuntivi ... che la funzione di lettore potrebbe aver bisogno

fsample <- 
    function(fname, n, seed, header=FALSE, ..., reader=read.csv) 
{ 

I semi funzione il generatore di numeri casuali, apre una connessione, e legge in (opzionale) riga di intestazione

set.seed(seed) 
    con <- file(fname, open="r") 
    hdr <- if (header) { 
     readLines(con, 1L) 
    } else character() 

il passo successivo è quello di leggere in un pezzo di n righe, inizializzare un contatore del numero totale di linee viste

buf <- readLines(con, n) 
    n_tot <- length(buf) 

continuare a leggere in blocchi di n righe, fermandosi quando non v'è alcun ulteriore ingresso

repeat { 
     txt <- readLines(con, n) 
     if ((n_txt <- length(txt)) == 0L) 
      break 

Per ogni blocco, disegnare un campione di n_keep linee, con il numero di linee proporzionale alla frazione di linee totali nel pezzo corrente. Ciò garantisce che le linee vengano campionate in modo uniforme sul file. Se non ci sono linee da mantenere, passa al blocco successivo.

 n_tot <- n_tot + n_txt 
     n_keep <- rbinom(1, n_txt, n_txt/n_tot) 
     if (n_keep == 0L) 
      next 

scegliere il linee per mantenere, e le linee per sostituire e aggiornare il buffer

 keep <- sample(n_txt, n_keep) 
     drop <- sample(n, n_keep) 
     buf[drop] <- txt[keep] 
    } 

Quando l'ingresso dati è fatto, analizzare il risultato utilizzando il lettore e restituire il risultato

reader(textConnection(c(hdr, buf), header=header, ...) 
} 

La soluzione potrebbe essere resa più efficiente, ma un po 'più complicata, utilizzando e cercando interruzioni di linea come suggerito da Simon Urbanek su R-devel mailing list. Ecco la soluzione completa

fsample <- 
    function(fname, n, seed, header=FALSE, ..., reader = read.csv) 
{ 
    set.seed(seed) 
    con <- file(fname, open="r") 
    hdr <- if (header) { 
     readLines(con, 1L) 
    } else character() 

    buf <- readLines(con, n) 
    n_tot <- length(buf) 

    repeat { 
     txt <- readLines(con, n) 
     if ((n_txt <- length(txt)) == 0L) 
      break 

     n_tot <- n_tot + n_txt 
     n_keep <- rbinom(1, n_txt, n_txt/n_tot) 
     if (n_keep == 0L) 
      next 

     keep <- sample(n_txt, n_keep) 
     drop <- sample(n, n_keep) 
     buf[drop] <- txt[keep] 
    } 

    reader(textConnection(c(hdr, buf)), header=header, ...) 
} 
+0

Grazie per aver postato il tuo codice e grazie per l'eccellente documentazione. Potresti essere in grado di indicarmi un esempio con 'readBin'? Grazie! – Zach

Problemi correlati