2013-03-01 23 views
5

Jestem całkiem nowy dla R i próbuję użyć aggregate do wykonania kształtowania serii czasowych na ramce danych, na temat i dla każdej metryki w moim zestawie danych. Działa to pięknie, ale uważam, że wynik nie jest w formacie, który jest bardzo łatwy w użyciu. Chciałbym móc przekształcić wyniki z powrotem do tego samego formatu, co oryginalna ramka danych.Spłaszczanie/denormalizowanie wyniku funkcji agregującej R

Używanie zestawu danych przysłony jako przykład:

# 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) 

Ja tylko używając diff celu zilustrowania, że ​​mam funkcję, która kształtuje szereg czasowy, więc dostaję szereg czasowy możliwie różnej długości w postaci wynik i zdecydowanie nie ma jednej wartości zagregowanej (np. średnia).

Chciałbym przekształcić wynik, który wydaje się być matrycą, która ma komórki z wartościami na liście, do pierwotnej "płaskiej" ramki danych.

Jestem w większości ciekawa, jak sobie z tym poradzić z wynikami z aggregate, ale byłbym w porządku z rozwiązaniami, które robią wszystko w plyr lub reshape.

+0

Mówisz o szeregach czasowych .. i podajesz przykład oparty na tęczówce? !! zagregujesz używając diff? jaka jest racjonalność ... lepiej byłoby użyć jednego z pakietów szeregów czasowych (zoo, xts, ..) !! Naprawdę nie rozumiem, co chcesz zrobić. (Czytam twoje pytanie co najmniej 3 razy) – agstudy

+1

@agstudy, myślę, że * pytanie jest trochę związane z zachowaniem się 'agregatu' jeśli dasz mu działają jak 'summary' lub' fivenum' lub coś innego, co zwróci więcej niż jedną kolumnę. W takich przypadkach wynikiem jest * to, co * wygląda * jak wielokolumnowa 'data.frame', ale faktycznie jest' macierzą' jako kolumną w 'data.frame'. Zatem 'do.call (data.frame, ...)' powinno zrobić lewę, aby "spłaszczyć" wyjście. – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto dzięki. Wiem o co ci chodzi. – agstudy

Odpowiedz

2

Jak być może wiesz, aggregate działa na jednej kolumnie na raz. spodziewane jest pojedyncza wartość, i dziwne rzeczy dzieją się, gdy wrócisz wektorów długości różnej od 1.

Można to podzielić się z by aby uzyskać dane (z mniejszą liczbą wierszy niż w iris) i umieścić go z powrotem razem:

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) jest używany tak, jak robi to, co chcesz dla macierzy (ale nie dla ramek danych). Kluczową kwestią jest to, że funkcja zwraca inną liczbę rzędów niż każdy z nich w każdym Species w iris.

2

Najlepszym rozwiązaniem mogę myśleć w tym przypadku jest data.table:

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

A jeśli chcesz rozwiązanie plyr, to pomysł jest w zasadzie taka sama. Podziel przez Species i zastosuj diff do każdej kolumny.

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

Czy osoba oddelegowana mogłaby wyjaśnić przyczynę, aby spróbować ją poprawić? – Arun

1

Jeśli chciał powrócić jakieś pierwsze różnice wektorem o takiej samej długości jak wektora wejściowego, należy robić to z kolei AVE oraz anonimowej funkcji. Ponieważ diff zwraca wektor o innej długości, musisz go przedłużyć NA (lub wybranym przez Ciebie znacznikiem).

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 ... 

Jeśli chcesz, aby jako ramka danych po prostu owinąć wokół siebie data.frame. I byłby to dobry pomysł, aby to oryginalny grupowania Vector:

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

Oto, co rozumiem jako swój problem: Przy obecnym sposobie korzystania aggregate, masz matrix dla wyników „Sepal.Length” , "Sepal.Width" i tak dalej.

> 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 ... 

Ale w konsoli, który wyświetla jak co wygląda niczym data.frame z 197 kolumn.

Chcesz przekonwertować "iris_diff" na data.frame z 197 kolumnami. Oto w jaki sposób można to zrobić z istniejącym wyjście (sztuczka Podniosłem z @James, here na SO):

do.call(data.frame, iris_diff) 

Oto kilka pierwszych linii wyjścia kiedy patrzymy na str tego działania:

> 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 
Powiązane problemy