2015-07-11 8 views
13

Ho un frame di dati con una colonna ID, una colonna di data (12 mesi per ciascun ID) e ho 23 variabili numeriche. Vorrei ottenere la variazione percentuale per mese all'interno di ciascun ID. Sto usando il pacchetto quantmod per ottenere la variazione percentuale.Come posso calcolare la variazione percentuale all'interno di un gruppo per più colonne in R?

Ecco un esempio con solo tre colonne (per semplicità):

ID Date V1 V2 V3 
1 Jan 2 3 5 
1 Feb 3 4 6 
1 Mar 7 8 9 
2 Jan 1 1 1 
2 Feb 2 3 4 
2 Mar 7 8 8 

ho tentato di usare dplyr e la funzione summarise_each, ma che non ha avuto successo. Più in particolare, ho provato la seguente (treno è il nome del set di dati):

library(dplyr) 
library(quantmod) 

group1<-group_by(train,EXAMID) 

foo<-function(x){ 
    return(Delt(x)) 
} 

summarise_each(group1,funs(foo)) 

Ho anche cercato di utilizzare la funzione di fare dplyr, ma non ha avuto successo con che o (avendo una brutta notte indovina!).

Penso che il problema sia la funzione Delt. Se si sostituisce Delt con la funzione sum:

foo<-function(x){ 
     return(sum(x)) 
    } 
summarise_each(group1,funs(foo)) 

Il risultato è che ogni variabile è riassunta tutta la data per ogni ID. Quindi, come può la variazione percentuale mese su mese per ogni ID?

risposta

9

Che ne dici di utilizzare pct <- function(x) x/lag(x)? esempio,

pct(1:3) 
[1] NA 2.0 1.5 

Edit: Aggiungendo suggerimento di Frank

pct <- function(x) {x/lag(x)} 

dt %>% group_by(ID) %>% mutate_each(funs(pct), c(V1, V2, V3)) 

ID Date  V1  V2 V3 
1 Jan  NA  NA NA 
1 Feb 1.500000 1.333333 1.2 
1 Mar 2.333333 2.000000 1.5 
2 Jan  NA  NA NA 
2 Feb 2.000000 3.000000 4.0 
2 Mar 3.500000 2.666667 2.0 
+0

ottengo il seguente errore: Errore: in attesa di un singolo valore Questa è una buona idea però. – mmmmmmmmmm

+4

@cwh_UCF Usa mutate invece di riepilogare (che è progettato per restituire un singolo valore): 'DF%>% group_by (ID)%>% mutate_each (funs (pct), c (V1, V2, V3))' – Frank

+0

@ Frank non dovrebbe essere una risposta invece di un commento. Sto solo chiedendo :) –

9

Il problema si esegue in è perché i dati non è formattato in modo "ordinato". Hai osservazioni (V1: V3) che sono in colonne creando un frame di dati "ampio". Il "tidyverse" funziona al meglio con il formato lungo. La buona notizia è che con la funzione gather() puoi ottenere esattamente ciò di cui hai bisogno. Ecco una soluzione che utilizza il "tidyverse".


library(tidyverse) 

# Recreate data set 
df <- tribble(
    ~ID, ~Date, ~V1, ~V2, ~V3, 
    1, "Jan", 2, 3, 5, 
    1, "Feb", 3, 4, 6, 
    1, "Mar", 7, 8, 9, 
    2, "Jan", 1, 1, 1, 
    2, "Feb", 2, 3, 4, 
    2, "Mar", 7, 8, 8 
) 
df 
#> # A tibble: 6 × 5 
#>  ID Date V1 V2 V3 
#> <dbl> <chr> <dbl> <dbl> <dbl> 
#> 1  1 Jan  2  3  5 
#> 2  1 Feb  3  4  6 
#> 3  1 Mar  7  8  9 
#> 4  2 Jan  1  1  1 
#> 5  2 Feb  2  3  4 
#> 6  2 Mar  7  8  8 

# Gather and calculate percent change 
df %>% 
    gather(key = key, value = value, V1:V3) %>% 
    group_by(ID, key) %>% 
    mutate(lag = lag(value)) %>% 
    mutate(pct.change = (value - lag)/lag) 
#> Source: local data frame [18 x 6] 
#> Groups: ID, key [6] 
#> 
#>  ID Date key value lag pct.change 
#> <dbl> <chr> <chr> <dbl> <dbl>  <dbl> 
#> 1  1 Jan V1  2 NA   NA 
#> 2  1 Feb V1  3  2 0.5000000 
#> 3  1 Mar V1  7  3 1.3333333 
#> 4  2 Jan V1  1 NA   NA 
#> 5  2 Feb V1  2  1 1.0000000 
#> 6  2 Mar V1  7  2 2.5000000 
#> 7  1 Jan V2  3 NA   NA 
#> 8  1 Feb V2  4  3 0.3333333 
#> 9  1 Mar V2  8  4 1.0000000 
#> 10  2 Jan V2  1 NA   NA 
#> 11  2 Feb V2  3  1 2.0000000 
#> 12  2 Mar V2  8  3 1.6666667 
#> 13  1 Jan V3  5 NA   NA 
#> 14  1 Feb V3  6  5 0.2000000 
#> 15  1 Mar V3  9  6 0.5000000 
#> 16  2 Jan V3  1 NA   NA 
#> 17  2 Feb V3  4  1 3.0000000 
#> 18  2 Mar V3  8  4 1.0000000 
+0

Questo dovrebbe essere il risposta accettata, p. – d8aninja