2013-03-01 2 views
5

Я довольно новичок в R, и я пытаюсь использовать aggregate для выполнения некоторых временных рядов, формирующих данные, по каждому предмету и каждой метрике в моем наборе данных. Это прекрасно работает, но я считаю, что результат не в формате, который очень прост в использовании. Я хотел бы иметь возможность преобразовать результаты обратно в тот же формат, что и исходный фрейм.Сгладить/denormalize результат функции агрегирования R

Использование диафрагмы набора данных в качестве примера:

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

Я просто с помощью diff, чтобы показать, что у меня есть функция, которая формирует временные ряды, так что я получаю временной ряд, возможно, разной длины в виде результат и определенно не одно совокупное значение (например, среднее значение).

Я хотел бы преобразовать результат, который, кажется, представляет собой матрицу, которая имеет список, ценные ячейки, в исходный «плоский» фрейм.

Мне больше всего любопытно, как управлять этим с результатами от aggregate, но я был бы в порядке с решениями, которые делают все в plyr или reshape.

+0

Вы говорите о временах серий..и вы приводите пример на основе радужки? !! вы объединяете с помощью diff? в чем смысл ... лучше было бы использовать один из пакетов временных рядов (зоопарк, xts, ..) !! действительно я не понимаю, что вы хотите сделать (я читаю ваш вопрос как минимум 3 раза) – agstudy

+1

@agstudy, я * думаю * вопрос немного связан с тем, как 'aggregate' ведет себя, если вы дадите ему как 'summary' или' fivenum' или что-то еще, что вернет более одного столбца. В таких случаях результатом является то, что * выглядит * как многоколоночный 'data.frame', но на самом деле является« матрицей »в качестве столбца в' data.frame'. Таким образом, 'do.call (data.frame, ...)' должен делать трюк, чтобы «сгладить» вывод. – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto спасибо. Я понимаю. – agstudy

ответ

2

Как вы знаете, aggregate работает по одной колонке за раз. Единственное значение, как ожидается, и странные вещи случаются, если вы возвращаетесь векторов длины, отличной от 1.

Вы можете разделить это с by, чтобы получить данные (с меньшим количеством строк, чем в iris) и положить его обратно вместе:

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) используется как это делает то, что вы хотите для матриц (но не для фреймов данных). Ключевым моментом является то, что функция возвращает другое количество строк, чем в каждом Species, в iris.

2

Лучшее решение, которое я мог думать в этом случае data.table:

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

И если вы хотите plyr решение, то идея в принципе то же самое. Разделите на Species и примените diff к каждому столбцу.

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

Может ли проголосователю объяснить причину, чтобы я мог попытаться ее исправить ?? – Arun

1

Если вы хотите, чтобы вернуть какую-то первые разности вектора с одной и той же длины, что и входной вектор, вы должны делать это с пр и анонимной функции. Поскольку diff возвращает вектор другой длины, вам нужно расширить его с помощью NA (или маркера по вашему выбору).

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

Если вы хотите, что в качестве dataframe просто обернуть data.frame вокруг него. И это было бы хорошей идеей, чтобы включать в себя оригинальную группировку вектор:

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

Вот что я понимаю, как ваша проблема: С вашим текущим методом использования aggregate, вы получите matrix за результаты «Sepal.Length» , "Sepal.Width" и т. Д.

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

Но, в консоли, которая показывает, как то, что выглядит похож на data.frame с 197 колоннами.

Вы хотите преобразовать «iris_diff» в data.frame с 197 колонками. Вот как вы можете сделать это с помощью существующей продукции (трюк я взял из @James, here на SO):

do.call(data.frame, iris_diff) 

Вот первые несколько строк вывода, когда мы смотрим на str этого действия:

> 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