2015-05-31 14 views
5

I recently eseguito nella seguente operazione raggruppata: per ogni gruppo, i valori vengono assegnati con numeri distribuiti uniformemente tra -0,5 e 0,5 e se il gruppo ha un solo elemento allora è assegnato il valore 0. Per esempio, se ho avuto i seguenti gruppi osservati:Assegnare valori per gruppo quando tutto ciò che conta è il numero di membri del gruppo

g <- c("A", "A", "B", "B", "A", "C") 

valori poi mi aspetterei assegnati:

outcome <- c(-0.5, 0, -0.5, 0.5, 0.5, 0) 

le tre osservazioni nel gruppo a sono stati assegnati valori -0.5 , 0 e 0.5 (in ordine), i due osservano nel gruppo B sono stati assegnati valori -0.5 e 0.5 (in ordine) e l'osservazione nel gruppo C è stata assegnata al valore 0.

Normalmente quando eseguo un'operazione raggruppata su un vettore per ottenere un altro vettore, utilizzo il Funzione ave, con il modulo ave(data.vector, group.vector, FUN=function.to.apply.to.each.groups.data.vector.subset). Tuttavia in questa operazione tutto quello che devo sapere è il numero di membri nel gruppo, quindi non c'è lo data.vector. Di conseguenza, ho finito solo facendo un vettore di dati che ho ignorato nella mia chiamata a ave:

ave(rep(NA, length(g)), g, FUN=function(x) { 
    if (length(x) == 1) { 
    return(0) 
    } else { 
    return(seq(-0.5, 0.5, length=length(x))) 
    } 
}) 
# [1] -0.5 0.0 -0.5 0.5 0.5 0.0 

Mentre questo mi dà la risposta corretta, è ovviamente piuttosto insoddisfacente per bisogno di fare un vettore di dati che Allora ignoro. C'è un modo migliore per assegnare i valori per gruppo quando tutto ciò che conta è il numero di elementi nel gruppo?

+1

Con 'data.table' (o simile con' dplyr') si potrebbe fare 'as.data.table (g) [, res: = if (.N> 1) seq (-0.5, 0.5, length = .N) else 0, by = g] $ res' anche se non è sicuro se questo è meglio. –

+1

btw, è possibile eseguire 'g' su se stesso all'interno di' ave' e non è necessario creare un nuovo vettore, ad esempio 'as.numeric (ave (g, g, FUN = function (x) { if (lunghezza (x) == 1) { ritorno (0) } else { ritorno (ss (-0.5, 0.5, lunghezza = lunghezza (x))) }} )) ' –

+2

si potrebbe evitare il' se '' else' con 'ave (seq_along (g), g, FUN = function (x) seq (-0.5, 0.5, length = length (x)) * (length (x)! = 1) + 0L)' oppure 'library (dplyr); as.data.frame (g)%>% group_by (g)%>% mutate (val = seq (-0.5, 0.5, length = n()) * (n()! = 1) + 0L) ' – akrun

risposta

2

Dai commenti non sembra che ci sia una versione di ave che prende solo il gruppo e una funzione che viene chiamata con il numero di elementi in ogni gruppo. Suppongo che questo non sia particolarmente sorprendente poiché è un'operazione piuttosto specializzata.

Se dovessi fare questo spesso ho potuto rotolare la mia versione di ave con le proprietà desiderate come un sottile wrapper ave:

ave.len <- function(..., FUN) { 
    l <- list(...) 
    do.call("ave", c(list(x=rep(NA, length(l[[1]]))), l, FUN=function(x) FUN(length(x)))) 
} 

# Original operation, using @akrun's 1-line command for sequences 
g <- c("A", "A", "B", "B", "A", "C") 
ave.len(g, FUN=function(n) seq(-0.5, 0.5, length=n)* (n!=1)+0L) 
# [1] -0.5 0.0 -0.5 0.5 0.5 0.0 

# Group of size n has the n^th letter in the alphabet 
ave.len(g, FUN=function(n) rep(letters[n], n)) 
# [1] "c" "c" "b" "b" "c" "a" 

# Multiple groups via the ... argument (here everything's in own group) 
ave.len(g, 1:6, FUN=function(n) rep(letters[n], n)) 
# [1] "a" "a" "a" "a" "a" "a" 
Problemi correlati