2016-02-06 16 views
11

In R, desidero riepilogare i miei dati dopo averli raggruppati in base alle esecuzioni di una variabile x (ovvero ogni gruppo di dati corrisponde a un sottoinsieme di dati dove valori consecutivi x sono uguali). Ad esempio, si consideri il seguente frame di dati, dove voglio calcolare il valore medio y all'interno di ogni serie di x:Utilizzare rle per raggruppare per esecuzione quando si utilizza dplyr

(dat <- data.frame(x=c(1, 1, 1, 2, 2, 1, 2), y=1:7)) 
# x y 
# 1 1 1 
# 2 1 2 
# 3 1 3 
# 4 2 4 
# 5 2 5 
# 6 1 6 
# 7 2 7 

In questo esempio, la variabile x ha percorsi di lunghezza 3, poi 2, poi 1, e infine 1, prendendo i valori 1, 2, 1 e 2 in queste quattro corse. I corrispondenti mezzi di y di tali gruppi sono 2, 4,5, 6, e 7.

È facile eseguire questa operazione raggruppati in base di R utilizzando tapply, passando dat$y i dati, utilizzando rle per calcolare il numero di esecuzione da dat$x, e passando la funzione di riepilogo desiderata:

tapply(dat$y, with(rle(dat$x), rep(seq_along(lengths), lengths)), mean) 
# 1 2 3 4 
# 2.0 4.5 6.0 7.0 

ho pensato che sarei in grado di trasportare abbastanza direttamente sopra questa logica a dplyr, ma i miei tentativi finora hanno tutti finito in errori:

library(dplyr) 
# First attempt 
dat %>% 
    group_by(with(rle(x), rep(seq_along(lengths), lengths))) %>% 
    summarize(mean(y)) 
# Error: cannot coerce type 'closure' to vector of type 'integer' 

# Attempt 2 -- maybe "with" is the problem? 
dat %>% 
    group_by(rep(seq_along(rle(x)$lengths), rle(x)$lengths)) %>% 
    summarize(mean(y)) 
# Error: invalid subscript type 'closure' 

Per completezza, ho potuto reimplementare l'id rle run me stesso usando cumsum, head, e tail per aggirare questo, ma rende il codice di raggruppamento più difficile da leggere e coinvolge un po 'di reinventare la ruota:

dat %>% 
    group_by(run=cumsum(c(1, head(x, -1) != tail(x, -1)))) %>% 
    summarize(mean(y)) 
#  run mean(y) 
# (dbl) (dbl) 
# 1  1  2.0 
# 2  2  4.5 
# 3  3  6.0 
# 4  4  7.0 

Qual è il motivo per cui il codice di raggruppamento basato su rle non funziona in dplyr e esiste una soluzione che mi consenta di continuare a utilizzare rle durante il raggruppamento per ID di esecuzione?

risposta

7

Una possibilità sembra essere l'uso di {} come in:

dat %>% 
    group_by(yy = {yy = rle(x); rep(seq_along(yy$lengths), yy$lengths)}) %>% 
    summarize(mean(y)) 
#Source: local data frame [4 x 2] 
# 
#  yy mean(y) 
# (int) (dbl) 
#1  1  2.0 
#2  2  4.5 
#3  3  6.0 
#4  4  7.0 

Sarebbe bello se il futuro dplyr versioni ha avuto anche un equivalente della funzione di data.table rleid.


ho notato che questo problema si verifica quando si utilizza un ingresso data.frame o tbl_df ma non, quando si utilizza un ingresso tbl_dt o data.table:

dat %>% 
    tbl_df %>% 
    group_by(yy = with(rle(x), rep(seq_along(lengths), lengths))) %>% 
    summarize(mean(y)) 
Error: cannot coerce type 'closure' to vector of type 'integer' 

dat %>% 
    tbl_dt %>% 
    group_by(yy = with(rle(x), rep(seq_along(lengths), lengths))) %>% 
    summarize(mean(y)) 
Source: local data table [4 x 2] 

    yy mean(y) 
    (int) (dbl) 
1  1  2.0 
2  2  4.5 
3  3  6.0 
4  4  7.0 

ho segnalato questo come un issue a pagina GitHub di dplyr.

+2

Sembra che il problema sia stato chiuso come esempio di https://github.com/hadley/dplyr/issues/1400, su cui sembrano funzionare. – josliber

+1

Questo è fantastico. Puoi spiegarmi o indirizzarmi alla documentazione su come "{}" funziona all'interno del gruppo_di chiamare qui? Googling "dplyr {}" non è particolarmente efficace, ma forse c'è un nome di fantasia per questo tipo di chiamata qui? Grazie! – Jordan

+3

@Jordan, questa non è una funzione specifica di dplyr.È dalla base R e puoi controllare 'help (" {")' –

2

Se si crea esplicitamente un raggruppamento variabile g più o meno opere:

> dat %>% transform(g=with(rle(dat$x),{ rep(seq_along(lengths), lengths)}))%>%         
group_by(g) %>% summarize(mean(y)) 
Source: local data frame [4 x 2] 

     g mean(y) 
    (int) (dbl) 
1  1  2.0 
2  2  4.5 
3  3  6.0 
4  4  7.0 

Ho usato transform qui perché mutate tiri un errore.

Problemi correlati