первая строка для неагрегатных функций

#r #plyr

#r #plyr

Вопрос:

Я использую ddply, чтобы избежать избыточных вычислений.

Я часто имею дело со значениями, которые сохраняются в разделенных подмножествах, и выполняю неагрегатный анализ. Итак, чтобы избежать этого (игрушечный пример):

 ddply(baseball,.(id,year),function(x){paste(x$id,x$year,sep="_")})

Error in list_to_dataframe(res, attr(.data, "split_labels")) : 
  Results do not have equal lengths
  

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

 ddply(baseball,function(x){paste(x$id[1],x$year[1],sep="_")})
  

Есть ли другой подход или помощник, который я должен использовать? Этот синтаксис кажется неудобным.

Примечание: вставка в моем примере сделана просто для галочки — не воспринимайте это слишком буквально. Представьте, что это реальная функция:

 ddply(baseball,function(x){the_slowest_function_ever(x$id[1],x$year[1])})
  

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

1. я удивлен, что нет способа получить доступ к .variables изнутри функции

2. возникшая проблема: github.com/hadley/plyr/issues/68

Ответ №1:

В этом случае вы можете найти data.table немного проще и быстрее. Эквивалентом .() переменных является by= :

 DT[, { paste(id,year,sep="_") }, by=list(id,year) ]
  

или

 DT[, { do.call("paste",.BY) }, by=list(id,year) ]
  

Я показал {} , чтобы проиллюстрировать, что вы можете поместить любое (многострочное) анонимное тело в j (а не функцию), но в этих простых примерах вам не нужно {} .

Группирующие переменные имеют длину 1 внутри области видимости каждой группы (похоже, это то, о чем вы спрашиваете), для скорости и удобства. .BY также содержит группирующие переменные в одном объекте списка для общего доступа, когда by критерии определяются программно на лету; т. Е. Когда вы не знаете by переменные заранее.

Ответ №2:

Вы могли бы использовать:

 ddply(baseball, .(id, year), function(x){data.frame(paste(x$id,x$year,sep="_"))})
  

Когда вы возвращаете вектор, объединение его обратно в data.frame превращает каждую запись в столбец. Но существуют разные длины, поэтому не все они имеют одинаковое количество столбцов. Заключая ее в data.frame() , вы убедитесь, что ваша функция возвращает data.frame столбец, который вы хотите, вместо того, чтобы полагаться на неявное (и в данном случае неправильное) преобразование. Кроме того, вы можете легко присвоить имя новому столбцу в этой конструкции.

Обновить:

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

 ddply(baseball, .(id, year), function(x) {
  x <- x[1,]
  paste(x$id, x$year, sep="_")
})
  

Это будет (само по себе) иметь только одну строку для каждой комбинации id / year. Если вы хотите, чтобы в нем было столько же строк, сколько в оригинале, то вы можете объединить это с предыдущей идеей.

 ddply(baseball, .(id, year), function(x) {
  firstrow <- x[1,]
  data.frame(label=rep(paste(firstrow$id, firstrow$year, sep="_"), nrow(x)))
})