Циклы для создания новых переменных в ddply

#r #for-loop #plyr

#r #for-цикл #plyr

Вопрос:

Я использую ddply для агрегирования и суммирования переменных фрейма данных, и мне интересно пройтись по списку моего фрейма данных, чтобы создать новые переменные.

 new.data <- ddply(old.data, 
                  c("factor", "factor2"),
                  function(df)
                    c(a11_a10 = CustomFunction(df$a11_a10),
                      a12_a11 = CustomFunction(df$a12_a11),
                      a13_a12 = CustomFunction(df$a13_a12),
                      ...
                      ...
                      ...))
  

Есть ли у меня способ вставить цикл в ddply, чтобы я мог избежать записи каждой новой итоговой переменной, например

 for (i in 11:n) {
  paste("a", i, "_a", i - 1) = CustomFunction(..... )
}
  

Я знаю, что на самом деле это было бы сделано не так, но я просто хотел показать, как бы я это концептуализировал. Есть ли способ сделать это в функции, которую я вызываю в ddply, или через список?

ОБНОВЛЕНИЕ: Поскольку я новый пользователь, я не могу опубликовать ответ на свой собственный вопрос:

Мой ответ включает идеи из ответа Ника и комментария Исты:

 func <- function(old.data, min, max, gap) {
  varrange <- min:max
  usenames <- paste("a", varrange, "_a", varrange - gap, sep="")
  new.data <- ddply(old.data,
                    .(factor, factor2),
                    colwise(CustomFunction, c(usenames)))
}
  

Комментарии:

1. вероятно, вам нужен transform() or summarize() . страница справки для summarize показывает несколько хороших примеров.

2. @Chase — Re: подведите итог, я мог бы сделать для (i в 11: n) с помощью(old.data, summary(old.data[, вставить(«a», i, «_a», i — 1, sep =»»)], llist(фактор, factor2), пользовательская функция))

3. Если бы вы сделали свой пример воспроизводимым, это облегчило бы жизнь вашим потенциальным помощникам. В отсутствие рабочего примера я могу только догадываться, что вы ищете ?colwise (смотрите Примеры использования с ddply).

4. @ Ista — Спасибо, colwise — это именно то, что я искал, узнав о первоначальной загрузке Ником имен переменных в память.

5. 1 @Casey. чрезвычайно элегантный.

Ответ №1:

Основываясь на превосходном ответе @Nick, вот один из подходов к проблеме

 foo <- function(df){
  names   = paste("a", 11:n, "_a", 10:(n-1), sep = "")
  results = sapply(df[,names], CustomFunction)
}

new.data = ldply(dlply(old.data, c("factor", "factor2")), foo)
  

Вот пример приложения, использующего tips dataset в ggplot2 . Предположим, мы хотим вычислить среднее значение tip и total_bill с помощью комбинации sex и smoker , вот как будет работать код

 foo = function(df){names = c("tip", "total_bill"); sapply(df[,names], mean)}
new = ldply(dlply(tips, c("sex", "smoker")), foo)
  

Это приводит к выводу, показанному ниже

          .id      tip total_bill
1  Female.No 2.773519   18.10519
2 Female.Yes 2.931515   17.97788
3    Male.No 3.113402   19.79124
4   Male.Yes 3.051167   22.28450
  

Это то, что вы искали?

Комментарии:

1. @ Ramnath — Это именно то, что я ищу, ЗА исключением того, что я бы хотел, чтобы переменные factor / ID оставались разделенными. Я полагаю, что ответ, который я дал в своем обновлении, позволит мне это сделать, но вы четко ответили на мой вопрос и превратили пример в функцию, которую я попытаюсь адаптировать. Спасибо.

2. @Casey. Ваш ответ более элегантный!! Я поддержал это и дал бы ему 2, если бы мог. Отличная работа

3. И все это может быть сделано в одной строке с помощью colwise . Смотрите мой ответ.

Ответ №2:

Если я вас правильно понял, вы, по сути, хотите применить пользовательскую функцию к каждому столбцу в ddply data.frame.

Хорошая новость в том, что есть ddply функция, которая делает именно это. Это означает, что решение вашей проблемы сводится к одной строке:

Основываясь на превосходном примере @Ramnath:

 library(ggplot2)
customfunction <- mean
ddply(tips, .(sex, smoker), numcolwise(customfunction))

     sex smoker total_bill      tip     size
1 Female     No   18.10519 2.773519 2.592593
2 Female    Yes   17.97788 2.931515 2.242424
3   Male     No   19.79124 3.113402 2.711340
4   Male    Yes   22.28450 3.051167 2.500000
  

Причина, по которой это работает, заключается в том, что colwise превращает функцию, которая работает с вектором, в функцию, которая работает со столбцом в data.frame. Существует два варианта colwise : numcolwise работает только с числовыми столбцами и catcolwise работает с категориальными столбцами. Смотрите ?colwise для получения дополнительной информации.

Редактировать:

Я понимаю, что вы, возможно, не захотите применять функцию ко всем столбцам в вашем data.frame. Тем не менее, я нахожу этот синтаксис настолько простым, что моим общим подходом было бы изменить data.frame, в который я передаю ddply . Например, в следующем примере изменены подмножества примеров tips , чтобы исключить некоторые столбцы. Решение по-прежнему является однострочным:

 ddply(tips[, -2], .(sex, smoker), numcolwise(customfunction))

     sex smoker total_bill     size
1 Female     No   18.10519 2.592593
2 Female    Yes   17.97788 2.242424
3   Male     No   19.79124 2.711340
4   Male    Yes   22.28450 2.500000
  

Комментарии:

1. это работает, только если вы применяете функцию ко всем столбцам, отличным от тех, которые использовались для разделения. Если это действительно так для OP, то это было бы лучшим решением. В противном случае, я думаю, что решение, предложенное OP, является более общим.

2. @Ramnath, Согласен, и хорошая мысль. Тем не менее, в моем рабочем процессе я бы предпочел выполнить простое подмножество data.frame, а не несколько сложную часть кодирования. Я отредактировал свой ответ, чтобы отразить это.

3. у colwise есть cols аргумент, который принимает символьный вектор имен переменных…

Ответ №3:

Пошагово:

 varrange<-11:n
usenames<-paste("a", varrange, "_a", varrange - 1, sep="")
results<-sapply(usenames, function(curname){CustomFunction(df[,curname])})
names(results)<-usenames
  

Это то, чего вы хотите?

Комментарии:

1. спасибо за ваш ответ, но это не то, что я ищу. Я действительно хочу получить фрейм данных, который включает уникальные наблюдения для каждой комбинации «factor» и «factor2», и выходные данные моей пользовательской функции для каждой из моих переменных «a» для каждой уникальной комбинации моих двух факторов.

2. в основном я ищу функциональность ddply, но автоматизирую создание переменных с использованием цикла или подхода со списком.