2010-01-29 14 views
5

Tengo algunos datos que se parecen a los siguientes. Se agrupa por variable "Año" y quiero extraer los percentiles de cada observación del puntaje, con respecto al año de origen, preferiblemente como un vector.Percentil para cada observación w/r/t Agrupación de variables

Year Score 
2001 89 
2001 70 
2001 72 
2001 ... 
.......... 
2004 87 
2004 90 

etc.

¿Cómo puedo hacer esto? agregado no funcionará, y no creo que aplique tampoco funcionará.

Respuesta

14

seguimiento a la solución de Vince, también se puede hacer esto con plyr o by:

ddply(df, .(years), function(x) transform(x, percentile=ecdf(x$scores)(x$scores))) 
+0

+1 porque realmente debería pasar algo de tiempo con plyr –

+0

Esto es hermoso. Sabía que tenía que haber una forma de una sola línea para hacer esto, incluso si requiere cargar un paquete. –

+3

O un poco más simple: 'ddply (df,. (Years), transform, percentile = ecdf (scores) (scores))' – hadley

3

que puede ser malentendido, pero creo que se puede hacer de esta manera:

> years = c(2006, 2006, 2006, 2006, 2001, 2001, 2001, 2001, 2001) 
> scores = c(13, 65, 23, 34, 78, 56, 89, 98, 100) 
> tapply(scores, years, quantile) 
$`2001` 
    0% 25% 50% 75% 100% 
    56 78 89 98 100 

$`2006` 
    0% 25% 50% 75% 100% 
13.00 20.50 28.50 41.75 65.00 

¿Es esto así?

Me refiero al percentil real de cada observación . - Ryan Rosario

Editar:

Creo que esto puede hacerlo a continuación:

> tapply(scores, years, function(x) { f = ecdf(x); sapply(x, f) }) 
$`2001` 
[1] 0.4 0.2 0.6 0.8 1.0 

$`2006` 
[1] 0.25 1.00 0.50 0.75 

con sus datos:

> tapply(scores, years, function(x) { f = ecdf(x); sapply(x, f) }) 
$`2000` 
[1] 0.3333333 0.6666667 1.0000000 

$`2008` 
[1] 0.5 1.0 

Edición 2:

Este es probablemente más rápido:

tapply(scores, years, function(x) { f = ecdf(x); f(x) }) 

f() se vectorizado :-)

pasado, modificación, lo prometo :-). Si desea nombres:

> tapply(scores, years, function(x) { f = ecdf(x); r = f(x); names(r) <- x; r }) 
$`2000` 
    1000  1700  2000 
0.3333333 0.6666667 1.0000000 

$`2008` 
1500 2000 
0.5 1.0 
0

Encontré un método, pero requiere un bucle.

group.pctiles <- function(group.var, comparable) { 
    unique.vals <- unique(group.var) 
    pctiles <- vector(length = length(group.var)) 
    for (i in 1:length(unique.vals)) { 
     slice <- which(group.var == unique.vals[i]) 
     F <- ecdf(comparable[slice]) 
     group.pctiles <- F(comparable[slice]) 
     pctiles[slice] <- group.pctiles 
    } 
    return(pctiles) 
} 

group.var es la variable que agrupa los datos. En mi ejemplo en mi pregunta, es Año. comparable contiene los valores para los que queremos encontrar los percentiles. En mi pregunta, comparable sería Puntuación.

Para los siguientes datos, puedo conseguir el resultado a continuación:

Year,School,Fees 
2000,10,1000 
2008,1,1050 
2008,4,2000 
2000,3,1700 
2000,1,2000 

> group.pctiles(dat, dat$Year, dat$Fees) 
[1] 0.3333333 0.5000000 1.0000000 0.6666667 1.0000000 

Entonces, puedo cbind estos percentiles de nuevo en el hoja.de.datos original para el análisis, informes, etc.

Alguien tiene una solución que no requiere un bucle?

0

¿Qué tal algo como:

Year <- c(2000,2008,2008,2000,2000) 
Fees <- c(1000,1050,2000,1700,2000) 
dat <- data.frame(Fees,Year,result=NA) 
res <- tapply(Fees,Year,function(x) rank(x,ties.method="max")/length(x)) 
for(i in 1:length(res)) 
    dat[Year==as.numeric(names(res)[i]),"result"] <-res[[i]] 

que produce:

Fees Year result 
1 1000 2000 0.3333333 
2 1050 2008 0.5000000 
3 2000 2008 1.0000000 
4 1700 2000 0.6666667 
5 2000 2000 1.0000000 
1

Usted también puede hacer algo como esto:

# first I'll create two dummy variables (Year, Score) 
year <- rep(2001:2005, 2) 
score <- round(rnorm(10, 35, 3)) 

# then coerce variables to data frame 
d <- data.frame(year, score) 

# then you can use split() function to apply 
# function to each stratum of grouping variable 
sapply(split(score, year), function(x) quantile(x, probs=seq(.1, .9, .1))) 

salida será algo como esto:

 2001 2002 2003 2004 2005 
10% 34.3 32.1 34.3 29.6 36.1 
20% 34.6 32.2 34.6 30.2 36.2 
30% 34.9 32.3 34.9 30.8 36.3 
40% 35.2 32.4 35.2 31.4 36.4 
50% 35.5 32.5 35.5 32.0 36.5 
60% 35.8 32.6 35.8 32.6 36.6 
70% 36.1 32.7 36.1 33.2 36.7 
80% 36.4 32.8 36.4 33.8 36.8 
90% 36.7 32.9 36.7 34.4 36.9 

Puede utilizar la función t() para transponer filas y columnas, si lo prefiere. Escribir una función será una buena forma de abordar este tipo de problemas. Recomiendo encarecidamente el paquete plyr escrito por Hadley Wickam.

Espero que esto ayude! ¡Todo lo mejor!

7

Usando ave

ave(d1$scores, d1$year, FUN=function(x) ecdf(x)(x)) 
+0

Creo que esta es la mejor solución: usa una función de estadísticas y está en línea. ¡Bien hecho! – Vince

0

Usando data.table es bastante recta hacia adelante también. Solo por completitud y también como una manera fácil de encontrar la solución data.table.

library(data.table) 
year <- rep(2001:2005, 2) 
score <- round(rnorm(10, 35, 3)) 

dt <- data.table(score) 


dt[, .(Percentile = ecdf(score)(score)), by = list(year)] 
Cuestiones relacionadas