2013-03-01 20 views
5

Sono abbastanza nuovo su R e sto cercando di utilizzare aggregate per eseguire la modellazione di serie temporali su un dataframe, per oggetto e per ogni metrica nel mio set di dati. Funziona magnificamente, ma trovo che il risultato non sia in un formato molto facile da usare. Mi piacerebbe essere in grado di trasformare i risultati nello stesso formato del dataframe originale.Appiattisci/denormalizza il risultato della funzione di aggregazione R

Utilizzando il set di dati dell'iride come esempio:

# Split into two data frames, one for metrics, the other for grouping 
iris_species = subset(iris, select=Species) 
iris_metrics = subset(iris, select=-Species) 
# Compute diff for each metric with respect to its species 
iris_diff = aggregate(iris_metrics, iris_species, diff) 

sto solo usando diff per illustrare che ho una funzione che modella la serie temporale, in modo da ottenere una serie di tempo di durata possibilmente diverso come risultato e sicuramente non un singolo valore aggregato (es. media).

Mi piacerebbe trasformare il risultato, che sembra essere una matrice che ha un elenco di celle con valore al dataframe "piatto" originale.

Sono principalmente curioso di sapere come gestirlo con i risultati da aggregate, ma sarei ok con soluzioni che fanno tutto in plyr o reshape.

+0

Si parla di serie temporali .. e si dà un esempio basato su iris? !! ti aggreghi usando diff? Qual è la logica. Sarebbe meglio usare uno dei pacchetti delle serie temporali (zoo, xts, ..) !! davvero non capisco cosa vuoi fare (ho letto la tua domanda almeno 3 volte) – agstudy

+1

@agstudy, io * penso * la domanda è un po 'da fare con come si comporta l'aggregazione se la dai una funziona come 'summary' o' fivenum' o qualcos'altro che restituirà più di una colonna. In questi casi, il risultato è ciò che * sembra * come un 'data.frame' a più colonne, ma in realtà è una' matrice 'come una colonna in un 'data.frame'. Quindi, un 'do.call (data.frame, ...)' dovrebbe fare il trucco per "appiattire" l'output. – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto ringraziamenti. Ho capito il tuo punto. – agstudy

risposta

2

Come forse sapete, aggregate funziona su una colonna alla volta. E 'previsto un unico valore, e le cose strane accadere se si torna vettori di lunghezza diversa da 1.

È possibile dividere questo con by per ottenere i dati (con un minor numero di righe rispetto a iris) e metterlo di nuovo insieme:

b <- by(iris_metrics, iris_species, FUN=function(x) diff(as.matrix(x))) 
do.call(rbind, lapply(names(b), function(x) data.frame(Species=x, b[[x]]))) 

diff(as.matrix) viene utilizzato in quanto fa ciò che si desidera per le matrici (ma non per i frame di dati). Il punto chiave è che la funzione restituisce un numero diverso di righe rispetto a ciascuna in Species in iris.

2

La soluzione migliore che potrei pensare in questo caso è data.table:

require(data.table) 
dt <- data.table(iris, key="Species") 
dt.out <- dt[, lapply(.SD, diff), by=Species] 

E se si desidera una soluzione plyr, allora l'idea è fondamentalmente la stessa. Dividere per Species e applicare diff a ciascuna colonna.

require(plyr) 
ddply(iris, .(Species), function(x) do.call(cbind, lapply(x[,1:4], diff))) 
+0

Potrebbe il down-voter spiegare il motivo per cui potrei provare a correggerlo ?? – Arun

1

Se si voleva restituire una sorta di prime differenze di vettore con la stessa lunghezza del vettore di ingresso, si dovrebbe fare in modo di ave e una funzione anonima. Poiché diff restituisce un vettore di lunghezza diversa, è necessario estenderlo con NA (o un indicatore di tua scelta).

iris_diff = lapply(iris_metrics, 
     function(xx) ave(xx, iris_species, FUN=function(x) c(NA, diff(x))) ) 
str(iris_diff) 
#-------------- 
List of 4 
$ Sepal.Length: num [1:150] NA -0.2 -0.2 -0.1 0.4 ... 
$ Sepal.Width : num [1:150] NA -0.5 0.2 -0.1 0.5 0.3 -0.5 0 -0.5 0.2 ... 
$ Petal.Length: num [1:150] NA 0 -0.1 0.2 -0.1 ... 
$ Petal.Width : num [1:150] NA 0 0 0 0 0.2 -0.1 -0.1 0 -0.1 ... 

Se si voleva che come dataframe Basta avvolgere data.frame intorno ad esso. E sarebbe una buona idea includere il vettore raggruppamento originale:

iris_diff <- data.frame(Species= iris_species, iris_diff) 
str(iris_diff) 
#------ 
'data.frame': 150 obs. of 5 variables: 
$ Species  : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ... 
$ Sepal.Length: num NA -0.2 -0.2 -0.1 0.4 ... 
$ Sepal.Width : num NA -0.5 0.2 -0.1 0.5 0.3 -0.5 0 -0.5 0.2 ... 
$ Petal.Length: num NA 0 -0.1 0.2 -0.1 ... 
$ Petal.Width : num NA 0 0 0 0 0.2 -0.1 -0.1 0 -0.1 ... 
1

Ecco quello che ho capito come il vostro problema: Con il vostro attuale metodo di utilizzare aggregate, si ottiene un matrix per i risultati di "Sepal.Length" , "Sepal.Width" e così via.

> str(iris_diff) 
'data.frame': 3 obs. of 5 variables: 
$ Species  : Factor w/ 3 levels "setosa","versicolor",..: 1 2 3 
$ Sepal.Length: num [1:3, 1:49] -0.2 -0.6 -0.5 -0.2 0.5 ... 
$ Sepal.Width : num [1:3, 1:49] -0.5 0 -0.6 0.2 -0.1 0.3 -0.1 -0.8 -0.1 0.5 ... 
$ Petal.Length: num [1:3, 1:49] 0 -0.2 -0.9 -0.1 0.4 ... 
$ Petal.Width : num [1:3, 1:49] 0 0.1 -0.6 0 0 0.2 0 -0.2 -0.3 0 ... 

Ma, nella console, che consente di visualizzare come quello che sembra come un data.frame con 197 colonne.

Si desidera convertire "iris_diff" a data.frame con 197 colonne. Ecco come si può fare con l'output esistente (un trucco che ho preso da @James, here su SO):

do.call(data.frame, iris_diff) 

Ecco le prime righe dell'output quando vediamo il str di tale azione:

> str(do.call(data.frame, iris_diff)) 
'data.frame': 3 obs. of 197 variables: 
$ Species  : Factor w/ 3 levels "setosa","versicolor",..: 1 2 3 
$ Sepal.Length.1 : num -0.2 -0.6 -0.5 
$ Sepal.Length.2 : num -0.2 0.5 1.3 
$ Sepal.Length.3 : num -0.1 -1.4 -0.8 
$ Sepal.Length.4 : num 0.4 1 0.2 
$ Sepal.Length.5 : num 0.4 -0.8 1.1 
$ Sepal.Length.6 : num -0.8 0.6 -2.7 
$ Sepal.Length.7 : num 0.4 -1.4 2.4 
$ Sepal.Length.8 : num -0.6 1.7 -0.6 
$ Sepal.Length.9 : num 0.5 -1.4 0.5 
$ Sepal.Length.10: num 0.5 -0.2 -0.7 
Problemi correlati