2013-07-02 13 views
6

Mam następujące dane:konstruowania ciąg identyfikatora dla każdego wiersza danych

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

i chciałby uzyskać ten wynik (w sposób, który będzie współpracować z dowolną liczbą kolumn):

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 

Następujące prace, ale mam nadzieję znaleźć coś krótszego i bardziej czytelnego.

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 = "_")] 

Odpowiedz

3

jeden sposób, tylko nieco czystsze:

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

dzięki , to zdecydowanie bardziej czytelne z mniejszą liczbą zgłoszeń, aktualnym zwycięzcą R-golfa :) – eddi

+0

Myślę, że 'apply' zamieni' d' na macierz. Tak więc będą kopie i mniej wydajności. – Roland

+0

@Roland, masz rację, to wcale nie jest skuteczne. Alternatywą jest użycie 'by = names (d)', ale wtedy musisz wycofać wartości z powrotem do 'paste', lub musisz wyciągnąć' paste' na zewnątrz 'j' –

1

Aby uniknąć zapętlenia poprzez wiersze, można użyć to:

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)) 

Uwaga: f2 zainspirowany odpowiedzią @ Ricardo.

Wyniki:

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 

Edit Uwaga: poprzednia analiza porównawcza z N <- 1e3 nie wykazują dużej różnicy w czasie. Jeszcze raz dziękuję @eddi.

+0

hmm, I +1 ' bo to wydawało się słuszne, ale po testowaniu nie sądzę, żeby twoje 'f1' działało tak, jak jest – eddi

+0

o, ok, wystarczy zastąpić' d [, n] 'z' d [[n]] ' – eddi

+0

Dzięki, @eddi, poprawione. To nie było tak szybkie, jak myślałem :-( –

2

Oto podejście używając do.call('paste'), ale wymagające tylko jednego połączenia do paste

będę odniesienia na situtation gdzie kolumny są liczbami całkowitymi (jak to wydaje się bardziej sensowne przypadku testowego

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 
Powiązane problemy