2015-01-01 11 views
7

Sto cercando di aggiungere una riga di NA dopo ciascun gruppo di dati in R.Inserire una riga di NA dopo ogni gruppo di dati utilizzando data.table

Una domanda simile è stata posta in precedenza. Insert a blank row after each group of data.

La risposta accettata funziona bene anche in questo caso come segue.

group <- c("a","b","b","c","c","c","d","d","d","d") 
xvalue <- c(16:25) 
yvalue <- c(1:10) 
df <- data.frame(cbind(group,xvalue,yvalue)) 
df_new <- as.data.frame(lapply(df, as.character), stringsAsFactors = FALSE) 
head(do.call(rbind, by(df_new, df$group, rbind, NA)), -1) 
    group xvalue yvalue 
a.1  a  16  1 
a.2 <NA> <NA> <NA> 
b.2  b  17  2 
b.3  b  18  3 
b.31 <NA> <NA> <NA> 
c.4  c  19  4 
c.5  c  20  5 
c.6  c  21  6 
c.41 <NA> <NA> <NA> 
d.7  d  22  7 
d.8  d  23  8 
d.9  d  24  9 
d.10  d  25  10 

Come posso accelerare l'operazione utilizzando data.table per una grande data.frame?

risposta

8

Si potrebbe provare

df$group <- as.character(df$group) 
setDT(df)[, .SD[1:(.N+1)], by=group][is.na(xvalue), group:=NA][!.N] 
#  group xvalue yvalue 
#1:  a  16  1 
#2: NA  NA  NA 
#3:  b  17  2 
#4:  b  18  3 
#5: NA  NA  NA 
#6:  c  19  4 
#7:  c  20  5 
#8:  c  21  6 
#9: NA  NA  NA 
#10: d  22  7 
#11: d  23  8 
#12: d  24  9 
#13: d  25  10 

O come suggerito da @ David Arenburg

setDT(df)[, indx := group][, .SD[1:(.N+1)], indx][,indx := NULL][!.N] 

O

setDT(df)[df[,.I[1:(.N+1)], group]$V1][!.N] 

Oppure potrebbe essere ulteriormente semplificata basata su commenti @ di Eddi

setDT(df)[df[, c(.I, NA), group]$V1][!.N] 
+2

Questo è soluzione molto molto pulito, anche se penso che si potrebbe evitare guai con 'group' e solo creare qualche indice e lasciarlo lì (o sbarazzarsi di esso in seguito), forse qualcosa di simile a' setDT (df) [, indx: = .GRP, gruppo] [, .SD [1 :(. N + 1)], indx] ' –

+0

@DavidArenburg Grazie per il commento. Anche il tuo codice funziona. Grazie – akrun

+2

O semplicemente 'setDT (df) [, indx: = gruppo] [, .SD [1 :(. N + 1)], indx] [, indx: = NULL] []' –

5

Un modo ho potuto pensare è quello di costruire un vettore prima come segue:

foo <- function(x) { 
    o = order(rep.int(seq_along(x), 2L)) 
    c(x, rep.int(NA, length(x)))[o] 
} 
join_values = head(foo(unique(df_new$group)), -1L) 
# [1] "a" NA "b" NA "c" NA "d" 

E poi setkey() e join.

setkey(setDT(df_new), group) 
df_new[.(join_values), allow.cartesian=TRUE] 
#  group xvalue yvalue 
# 1:  a  16  1 
# 2: NA  NA  NA 
# 3:  b  17  2 
# 4:  b  18  3 
# 5: NA  NA  NA 
# 6:  c  19  4 
# 7:  c  20  5 
# 8:  c  21  6 
# 9: NA  NA  NA 
# 10:  d  22  7 
# 11:  d  23  8 
# 12:  d  24  9 
# 13:  d  25  10 
+0

Pensi che questo migliorerà le prestazioni in qualche modo? Perché la soluzione akrun mi sembra molto idiomatica –

+4

@DavidArenburg, non seguo il motivo per cui entrambi dovrebbero essere idiomatici * qui *. È solo un altro modo. Ho usato join perché dà la risposta direttamente, piuttosto che dover sostituire con NA in seguito. – Arun

Problemi correlati