2015-02-18 12 views
5

Questo è un piccolo esempio. Nel mio set di dati più grande, ho più anni di dati e il numero di osservazioni per gruppo (div) non è sempre uguale.dplyr classifica osservazioni su variabili

dati

Esempio:

set.seed(1) 
df<-data.frame(
    year = 2014, 
    id = sample(LETTERS[1:26], 12), 
    div = rep(c("1", "2a", "2b"), each=4), 
    pts = c(9,7,9,3,7,5,3,7,2,7,7,1), 
    x = c(10,12,11,7,7,5,4,12,4,6,7,2) 
) 

df

# year id div pts x 
#1 2014 G 1 9 10 
#2 2014 J 1 7 12 
#3 2014 N 1 9 11 
#4 2014 U 1 3 7 
#5 2014 E 2a 7 7 
#6 2014 S 2a 5 5 
#7 2014 W 2a 3 4 
#8 2014 M 2a 7 12 
#9 2014 L 2b 2 4 
#10 2014 B 2b 7 6 
#11 2014 D 2b 7 7 
#12 2014 C 2b 1 2 

voglio classificare questi dati in modo tale che gli individui in div 1 sono classificati superiore div 2a/2b, e all'interno di div 1 individui sono classificati 1,2,3,4 basato sul numero più alto di "pts" seguito dal numero più alto di "x".

Gli individui in div 2a e div 2b devono essere classificati individualmente anche sulla base degli stessi criteri. Questo sarebbe simile a questa:

df %>% 
    group_by(div) %>% 
    arrange(desc(pts), desc(x)) %>% 
    mutate(position = row_number(div)) 


# year id div pts x position 
#1 2014 N 1 9 11  1 
#2 2014 G 1 9 10  2 
#3 2014 J 1 7 12  3 
#4 2014 U 1 3 7  4 
#5 2014 M 2a 7 12  1 
#6 2014 E 2a 7 7  2 
#7 2014 S 2a 5 5  3 
#8 2014 W 2a 3 4  4 
#9 2014 D 2b 7 7  1 
#10 2014 B 2b 7 6  2 
#11 2014 L 2b 2 4  3 
#12 2014 C 2b 1 2  4 

Tuttavia, voglio produrre una colonna/variabile finale che è un altro grado. Questo posizionerebbe tutti gli individui in div 1 come superiori a 2a/2b, ma 2a/2b sono uguali. Ad esempio, le persone che sono 1 in 2a/2b dovrebbero ora ottenere 5,5, le persone che sono classificate 2 dovrebbero ora ottenere 7,5. Ci sono sempre un numero uguale di persone in div2a e div2b per tutti gli anni.

Esso dovrebbe essere simile a questo:

# year id div pts x position final 
#1 2014 N 1 9 11  1 1.0 
#2 2014 G 1 9 10  2 2.0 
#3 2014 J 1 7 12  3 3.0 
#4 2014 U 1 3 7  4 4.0 
#5 2014 M 2a 7 12  1 5.5 
#6 2014 E 2a 7 7  2 7.5 
#7 2014 S 2a 5 5  3 9.5 
#8 2014 W 2a 3 4  4 11.5 
#9 2014 D 2b 7 7  1 5.5 
#10 2014 B 2b 7 6  2 7.5 
#11 2014 L 2b 2 4  3 9.5 
#12 2014 C 2b 1 2  4 11.5 

Ho bisogno di trovare una soluzione dplyr ideale. Inoltre, è necessario generalizzare a anni in cui il numero di individui in 'div1' può variare e il numero di individui in div2a/div2b varia (sebbene lunghezza (div2a) == lunghezza (div2b) sempre).

risposta

7

Ecco come lo farei:

library(data.table) 
dt = as.data.table(df) 

dt[order(-pts, -x), rank.init := 1:.N, by = div] 

dt[, div.clean := sub('(\\d+).*', '\\1', div)] 
setorder(dt, div.clean, rank.init) 

dt[, rank.final := mean(.I), by = .(div.clean, rank.init)] 
setorder(dt, div, rank.final) 
# year id div pts x rank.init div.clean rank.final 
# 1: 2014 N 1 9 11   1   1  1.0 
# 2: 2014 G 1 9 10   2   1  2.0 
# 3: 2014 J 1 7 12   3   1  3.0 
# 4: 2014 U 1 3 7   4   1  4.0 
# 5: 2014 M 2a 7 12   1   2  5.5 
# 6: 2014 E 2a 7 7   2   2  7.5 
# 7: 2014 S 2a 5 5   3   2  9.5 
# 8: 2014 W 2a 3 4   4   2  11.5 
# 9: 2014 D 2b 7 7   1   2  5.5 
#10: 2014 B 2b 7 6   2   2  7.5 
#11: 2014 L 2b 2 4   3   2  9.5 
#12: 2014 C 2b 1 2   4   2  11.5 
+0

Grazie - entrambe le risposte sono eccezionali. Problemi come questo mi incoraggiano a familiarizzare con 'data.table' – jalapic

+0

anche - solo un chiarimento, se si vuole eseguire questo per più anni contemporaneamente nello stesso dt, il' by = div' deve essere 'by =. (div, anno) '? – jalapic

+0

@jalapic sì, e potrebbe essere necessario modificare l'ultimo 'mean', a seconda di cosa si desidera esattamente per più anni – eddi

5

@ risposta di Eddi è già molto bello. Volevo solo illustrare lo stesso usando la funzione frank() dalla versione di sviluppo di data.table, v1.9.5, che può calcolare ranghi su vettori, elenchi, data.frames o data.tables.

# from @eddi's 
setDT(df)[, div.clean := sub('(\\d+).*', '\\1', div)] 

df[, position := frank(.SD, -pts, -x, ties.method="first"), by=div] 
df[, final := frank(.SD, div.clean, position, ties.method="average")] 

mantiene questo anche l'ordine originale, se questo è di una certa importanza.

Lascio la conversione a dplyr.

Problemi correlati