Ho difficoltà ad aggregare un frame di dati mantenendo i gruppi nel loro ordine originale (ordine basato sulla prima apparizione nel frame di dati). Sono riuscito a farlo bene, ma speravo che ci fosse un modo più semplice per farlo.Insieme di dati aggregati mantenendo l'ordine originale, in modo semplice
ecco un insieme di dati campione da elaborare:
set.seed(7)
sel.1 <- sample(1:5, 20, replace = TRUE) # selection vector 1
sel.2 <- sample(1:5, 20, replace = TRUE)
add.1 <- sample(81:100) # additional vector 1
add.2 <- sample(81:100)
orig.df <- data.frame(sel.1, sel.2, add.1, add.2)
Alcuni punti da notare: ci sono due colonne di selezione per determinare come i dati vengono raggruppati insieme. Saranno lo stesso, e i loro nomi sono noti. Ho inserito solo due colonne aggiuntive in questi dati, ma potrebbero essercene di più. Ho dato i nomi delle colonne cominciando con 'sel' e 'add' per renderlo più facile da seguire, ma i dati effettivi hanno nomi diversi (quindi mentre i trucchi grep
sono fantastici, non saranno utili qui).
Quello che sto cercando di fare è aggregare il frame di dati in gruppi basati sulle colonne "sel" e sommare tutte le colonne "aggiungi". Questo è abbastanza semplice utilizzando aggregate
come segue:
# Get the names of all the additional columns
all.add <- names(orig.df)[!(names(orig.df)) %in% c("sel.1", "sel.2")]
aggr.df <- aggregate(orig.df[,all.add],
by=list(sel.1 = orig.df$sel.1, sel.2 = orig.df$sel.2), sum)
Il problema è che il risultato è ordinato dalle colonne 'SEL'; Lo voglio ordinato in base alla prima apparizione di ciascun gruppo nei dati originali.
Qui sono i miei migliori tentativi di fare questo lavoro:
## Attempt 1
# create indices for each row (x) and find the minimum index for each range
index.df <- aggregate(x = 1:nrow(orig.df),
by=list(sel.1 = orig.df$sel.1, sel.2 = orig.df$sel.2), min)
# Make sure the x vector (indices) are in the right range for aggr.df
index.order <- (1:nrow(index.df))[order(index.df$x)]
aggr.df[index.order,]
## Attempt 2
# get the unique groups. These are in the right order.
unique.sel <- unique(orig.df[,c("sel.1", "sel.2")])
# use sapply to effectively loop over data and sum additional columns.
sums <- t(sapply(1:nrow(unique.sel), function (x) {
sapply(all.add, function (y) {
sum(aggr.df[which(aggr.df$sel.1 == unique.sel$sel.1[x] &
aggr.df$sel.2 == unique.sel$sel.2[x]), y])
})
}))
data.frame(unique.sel, sums)
Mentre questi mi danno il risultato giusto, speravo che qualcuno potrebbe indicare una soluzione più semplice. Sarebbe preferibile se la soluzione funzionasse con i pacchetti forniti con l'installazione R standard.
Ho guardato la documentazione per aggregate
e match
, ma non riuscivo a trovare una risposta (immagino speravo in qualcosa di simile a un parametro "keep.original.order" per aggregate
).
Qualsiasi aiuto sarebbe molto apprezzato!
aggiornamento: (in caso qualcuno si imbatte in questo)
Ecco il modo più pulito che ho potuto trovare dopo aver provato per qualche giorno in più:
unique(data.frame(sapply(names(orig.df), function(x){
if(x %in% c("sel.1", "sel.2")) orig.df[,x] else
ave(orig.df[,x], orig.df$sel.1, orig.df$sel.2, FUN=sum)},
simplify=FALSE)))
Grazie per l'aggiornamento, questo è forse il più bello breve soluzione di utilizzare data.table. Come si fa a peggiorare il team di sviluppo R per implementare un parametro 'keep.original.order' per l'aggregato? Sembra una chiara svista –