2013-02-18 9 views
10

Ho un sacco di dati. Tabelle in una lista. Voglio applicare unique() a ogni data.table nel mio elenco, ma così facendo distruggo tutte le mie chiavi data.table.Perché lapply() non conserva le chiavi data.table?

Ecco un esempio:

A <- data.table(a = rep(c("a","b"), each = 3), b = runif(6), key = "a") 
B <- data.table(x = runif(6), b = runif(6), key = "x") 

blah <- unique(A) 

Qui, blah ha ancora una chiave, e tutto ciò che si trova proprio nel mondo:

key(blah) 

# [1] "a" 

Ma se aggiungo le data.tables per una lista e utilizzare lapply(), i tasti vengono distrutti:

dt.list <- list(A, B) 

unique.list <- lapply(dt.list, unique) # Keys destroyed here 

lapply(unique.list, key) 

# [[1]] 
# NULL 

# [[2]] 
# NULL 

Questo probabilmente ha a che non capisco veramente cosa significhi assegnare le chiavi "per riferimento", perché ho avuto altri problemi con le chiavi che scompaiono.

Quindi:

  • Perché lapply non mantenere le mie chiavi?
  • Che cosa significa dire che i tasti sono assegnati "per riferimento"?
  • Devo anche memorizzare dati in una lista?
  • Come posso archiviare/manipolare in modo sicuro data.tables senza timore di perdere le mie chiavi?

EDIT:

Per quello che vale, il temuto for circuito funziona bene, anche:

unique.list <- list() 

for (i in 1:length(dt.list)) { 
    unique.list[[i]] <- unique(dt.list[[i]]) 
} 

lapply(unique.list, key) 

# [[1]] 
# [1] "a" 

# [[2]] 
# [1] "x" 

Ma questo è R, e for loop sono male.

+1

interessante, 'unique.list [[1]]! = Unique (A)'. La mia ipotesi, anche se è semplicemente un'ipotesi, è che forse ciò che viene chiamato nell'istruzione lapply è l'unico '{base}' e non il '{data.table}' 'unique'. –

+0

Penso che tu abbia ragione. Ho appena notato che - unitamente alle chiavi distrutte - 'unique' non sta nemmeno facendo il suo lavoro quando passa attraverso' lapply' –

+1

@PaulMurray +1 Buona domanda, ma _destroy_ sembra un po 'forte. In questo caso, non li restituisce. –

risposta

9

È interessante notare che, notare la differenza tra questi due differenti risultati

lapply(dt.list, unique) 
lapply(dt.list, function(x) unique(x)) 

Se si utilizza la seconda, i risultati sono come ci si aspetterebbe.


Il comportamento apparentemente imprevisto è dovuto al fatto che la prima affermazione è lapply invocando unique.data.frame (vale a dire da {base}), mentre il secondo sta invocando unique.data.table

+0

Wow, grazie. E * strano *. Funziona come una soluzione, ma voglio ancora sapere cosa sta succedendo. Sono l'unico che vuole memorizzare data.tables nelle liste? Ho intenzione di presentare questo come un [bug report] (https://r-forge.r-project.org/tracker/?atid=975&group_id=240&func=browse) - pensi che sia giusto? –

+1

@Plmrry Penso che quando si memorizza la lista 'data.table's, si perde un grande vantaggio di quali offerte data.table, ovvero l'efficienza della memoria evitando duplicazioni inutili. Personalmente, memorizzo un elenco dei ** nomi ** dei miei dati.tables e li prendo da 'get (' * name * ')'. Un codice un po 'più brutto, ma più veloce. –

+0

@Plmrry come per il bug report, potrebbe non essere un bug, ma solo il modo in cui 'match.fun()' funziona. Non posso dire però –

5

Buona domanda. Si scopre che è documentato in ?lapply (vedere la sezione Nota):

Per ragioni storiche, le chiamate create da lapply sono non valutata, e il codice è stato scritto (per esempio bquote) che si basa su questo. Questo significa che la chiamata registrata è sempre nella forma FUN (X [[0L]], ...), con 0L sostituito dall'indice intero corrente. Questo non è normalmente un problema , ma può essere se FUN utilizza sys.call o match.call o se è una funzione primitiva che utilizza la chiamata.Ciò significa che è spesso più sicuro chiamare le funzioni primitive con un wrapper, in modo tale che ad es. lapply (ll, function (x) is.numeric (x)) è richiesto in R 2.7.1 per assicurare che il metodo di invio per is.numeric si verifica correttamente.

+0

Grazie! Certo che era nel manuale da sempre ... –

Problemi correlati