2013-07-02 15 views
6

ho i seguenti dati:costruire una stringa di identificazione per ciascuna riga di dati

library(data.table) 
d = data.table(a = c(1:3), b = c(2:4)) 

e vorrebbe ottenere questo risultato (in modo tale da funzionare con numero arbitrario di colonne):

d[, c := paste0('a_', a, '_b_', b)] 
d 
# a b  c 
#1: 1 2 a_1_b_2 
#2: 2 3 a_2_b_3 
#3: 3 4 a_3_b_4 

I seguenti lavori, ma spero di trovare qualcosa di più breve e più leggibile.

d = data.table(a = c(1:3), b = c(2:4)) 
d[, c := apply(mapply(paste, names(.SD), .SD, MoreArgs = list(sep = "_")), 
       1, paste, collapse = "_")] 

risposta

3

un modo, solo un po 'più pulito:

d[, c := apply(d, 1, function(x) paste(names(d), x, sep="_", collapse="_")) ] 

    a b  c 
1: 1 2 a_1_b_2 
2: 2 3 a_2_b_3 
3: 3 4 a_3_b_4 
+0

grazie , questo è sicuramente più leggibile con meno applica, vincitore del R-golf attuale :) – eddi

+0

Penso che 'apply' convertirà' d' in una matrice. Quindi, ci saranno copie e meno efficienza. – Roland

+0

@Roland, sei corretto, questo non è affatto efficiente. Un'alternativa è usare 'by = names (d)' ma poi devi reinserire i valori in 'paste', o devi tirare' paste' all'esterno di 'j' –

1

Per evitare scorrendo le righe, è possibile utilizzare questo:

do.call(paste, c(lapply(names(d), function(n)paste0(n,"_",d[[n]])), sep="_"))

Benchmarking:

N <- 1e4 

d <- data.table(a=runif(N),b=runif(N),c=runif(N),d=runif(N),e=runif(N)) 

f1 <- function(d) 
{ 
    do.call(paste, c(lapply(names(d), function(n)paste0(n,"_",d[[n]])), sep="_")) 
} 

f2 <- function(d) 
{ 
    apply(d, 1, function(x) paste(names(d), x, sep="_", collapse="_")) 
} 

require(microbenchmark) 

microbenchmark(f1(d), f2(d)) 

Nota: f2 ispirato alla risposta di @ Ricardo.

Risultati:

Unit: milliseconds 
    expr  min  lq median  uq  max neval 
f1(d) 195.8832 213.5017 216.3817 225.4292 254.3549 100 
f2(d) 418.3302 442.0676 451.0714 467.5824 567.7051 100 

modifica nota: l'analisi comparativa precedente con N <- 1e3 non ha mostrato molta differenza nei tempi. Grazie ancora @eddi.

+0

hmm, I +1 ' d perché sembrava giusto, ma dopo aver provato, non penso che il tuo 'f1' funzioni come lo è – eddi

+0

oh ok, devi solo sostituire' d ​​[, n] 'con' d [[n]] ' – eddi

+0

Grazie, @eddi, corretto. Non è stato veloce come pensavo :-( –

2

Ecco un approccio utilizzando do.call('paste'), ma richiede solo una singola chiamata a paste

io benchmark su un situtation cui le colonne sono interi (come questo sembra un test più sensibile

N <- 1e4 

d <- setnames(as.data.table(replicate(5, sample(N), simplify = FALSE)), letters[seq_len(5)]) 

f5 <- function(d){ 
    l <- length(d) 
    o <- c(1L, l + 1L) + rep_len(seq_len(l) -1L, 2L * l) 
    do.call('paste',c((c(as.list(names(d)),d))[o],sep='_'))} 


microbenchmark(f1(d), f2(d),f5(d)) 
Unit: milliseconds 
    expr  min  lq median  uq  max neval 
f1(d) 41.51040 43.88348 44.60718 45.29426 52.83682 100 
f2(d) 193.94656 207.20362 210.88062 216.31977 252.11668 100 
f5(d) 30.73359 31.80593 32.09787 32.64103 45.68245 100 
Problemi correlati