Давайте возьмем следующие данные:R: использование data.table: = операции для вычисления новых столбцов
dt <- data.table(TICKER=c(rep("ABC",10),"DEF"),
PERIOD=c(rep(as.Date("2010-12-31"),10),as.Date("2011-12-31")),
DATE=as.Date(c("2010-01-05","2010-01-07","2010-01-08","2010-01-09","2010-01-10","2010-01-11","2010-01-13","2010-04-01","2010-04-02","2010-08-03","2011-02-05")),
ID=c(1,2,1,3,1,2,1,1,2,2,1),VALUE=c(1.5,1.3,1.4,1.6,1.4,1.2,1.5,1.7,1.8,1.7,2.3))
setkey(dt,TICKER,PERIOD,ID,DATE)
Теперь для каждой комбинации тикер/период, мне нужно следующее в новом столбце:
PRIORAVG
: Среднее значение из VALUE каждого идентификатора, за исключением текущего идентификатора, при условии, что оно не превышает 180 дней.PREV
: Предыдущее значение из того же ID.
Результат должен выглядеть следующим образом:
TICKER PERIOD DATE ID VALUE PRIORAVG PREV
[1,] ABC 2010-12-31 2010-01-05 1 1.5 NA NA
[2,] ABC 2010-12-31 2010-01-08 1 1.4 1.30 1.5
[3,] ABC 2010-12-31 2010-01-10 1 1.4 1.45 1.4
[4,] ABC 2010-12-31 2010-01-13 1 1.5 1.40 1.4
[5,] ABC 2010-12-31 2010-04-01 1 1.7 1.40 1.5
[6,] ABC 2010-12-31 2010-01-07 2 1.3 1.50 NA
[7,] ABC 2010-12-31 2010-01-11 2 1.2 1.50 1.3
[8,] ABC 2010-12-31 2010-04-02 2 1.8 1.65 1.2
[9,] ABC 2010-12-31 2010-08-03 2 1.7 1.70 1.8
[10,] ABC 2010-12-31 2010-01-09 3 1.6 1.35 NA
[11,] DEF 2011-12-31 2011-02-05 1 2.3 NA NA
Обратите внимание на PRIORAVG
по строке 9 равен 1,7 (что равно VALUE
на строке 5, которая является единственным перед наблюдением в прошлом 180 дней другим ID
)
Я обнаружил пакет data.table
, но я не могу полностью понять функцию :=
. Когда я держу это просто, это работает. Для того, чтобы получить предыдущее значение для каждого идентификатора (я на основе этого на решение this question):
dt[,PREV:=dt[J(TICKER,PERIOD,ID,DATE-1),roll=TRUE,mult="last"][,VALUE]]
Это прекрасно работает, и это занимает всего 0,13 секунды, чтобы выполнить эту операцию над моим набором данных с ~ 250K строк; моя функция векторного сканирования получает одинаковые результаты, но примерно в 30 000 раз медленнее.
Итак, у меня есть мое первое требование. Давайте перейдем ко второму, более сложному требованию. Прямо сейчас постиженный метод до сих пор использует пару векторных сканов и бросает функцию через функцию plyr
adply
, чтобы получить результат для каждой строки.
calc <- function(df,ticker,period,id,date) {
df <- df[df$TICKER == ticker & df$PERIOD == period
& df$ID != id & df$DATE < date & df$DATE > date-180, ]
df <- df[order(df$DATE),]
mean(df[!duplicated(df$ID, fromLast = TRUE),"VALUE"])
}
df <- data.frame(dt)
adply(df,1,function(x) calc(df,x$TICKER,x$PERIOD,x$ID,x$DATE))
Я написал функцию для data.frame
и это не похоже на работу с data.table
. Для подмножества 5000 строк это занимает около 44 секунд, но мои данные состоят из> 1 миллиона строк. Интересно, может ли это быть более эффективным благодаря использованию :=
.
dt[J("ABC"),last(VALUE),by=ID][,mean(V1)]
Это работает, чтобы выбрать среднее значение из последних значений VALUE для каждого идентификатора для ABC.
dt[,PRIORAVG:=dt[J(TICKER,PERIOD),last(VALUE),by=ID][,mean(V1)]]
Это, однако, не работает, как и следовало ожидать, поскольку она занимает среднее значение всех последних значений для всех тикер/периодов вместо только для текущего тикер/период. Таким образом, он заканчивается тем, что все строки получают одинаковое среднее значение. Я что-то делаю неправильно или это ограничение :=
?
Подсказки: присоедините унаследованную область для преобладающего наблюдения за последние 180 дней (с использованием префикса 'i.':' [, j = list (..., age = PERIOD-i.PERIOD, ...),] [age <180] 'и' mult = "last" ', а не' last() ', может быть. –
Кажется, что панель данных по-разному связана с выпиской кода над ней, а в ней отсутствует') ' кажется. –
добавлены данные, которые показывают ожидаемые результаты в течение 180 дней. – Dirk