Строки подмножества, соответствующие максимальному значению по группе с использованием data.table

Предположим, у меня есть data.table, в котором есть несколько бейсболистов:

library(plyr)
library(data.table)

bdt <- as.data.table(baseball)

Для каждой группы (заданной идентификатором игрока) я хочу выбрать строки, соответствующие максимальному количеству игр «g». Это просто в plyr:

ddply(baseball, "id", subset, g == max(g))

Какой эквивалентный код для data.table?

Я пытался:

setkey(bdt, "id") 
bdt[g == max(g)]  # only one row
bdt[g == max(g), by = id]  # Error: 'by' or 'keyby' is supplied but not j
bdt[, .SD[g == max(g)]] # only one row

Это работает:

bdt[, .SD[g == max(g)], by = id] 

Но это всего лишь на 30% быстрее, чем plyr, что говорит о том, что это, вероятно, не идиоматично.


person hadley    schedule 15.05.2013    source источник
comment
Вау, это медленно, но если вы используете год вместо .SD ... Я получаю 0,01, 1,58, 2,39 пользовательского времени для года, .SD, plyr соответственно.   -  person Frank    schedule 16.05.2013
comment
@Frank, но мне нужен весь фрейм данных, а не только год. Уточню вопрос.   -  person hadley    schedule 16.05.2013


Ответы (1)


Вот быстрый data.table способ:

bdt[bdt[, .I[g == max(g)], by = id]$V1]

Это позволяет избежать построения .SD, которое является узким местом в ваших выражениях.

edit: На самом деле, основная причина того, что OP работает медленно, заключается не только в том, что он содержит .SD, но и в том, что он использует его определенным образом - путем вызова [.data.table, который на данный момент имеет огромные накладные расходы, поэтому запуск его в цикле (когда кто-то делает by) накапливает очень большой штраф.

person eddi    schedule 15.05.2013
comment
+1 Держу пари, что Хэдли хочет сделать это несколько программно, и в этом случае он захочет использовать этот синтаксис, bdt[bdt[, .I[g == max(g)], by = id][,V1]] верно? - person joran; 16.05.2013
comment
@joran Я создаю вызов вручную, так что это не имеет особого значения - person hadley; 16.05.2013
comment
Со временем первоначальный подход будет оптимизирован. См. FR 2330 Оптимизировать .SD[i] запрос, чтобы сохранить элегантность, но сделать его быстрее без изменений. - person mnel; 16.05.2013
comment
Ссылка на эту проблему с тех пор перемещена из R-Forge в GitHub здесь # 613 - person Matt Dowle; 23.02.2016
comment
Если я добавлю verbose = TRUE во внутренний фрейм, я увижу GForce FALSE, но он все равно быстрее, чем что-то вроде bdt[bdt[, .(g=max(g)), by=id], on=c("id","g")], хотя я не знаю, всегда ли так будет. - person Alexis; 06.07.2019