Получить (t-1) данные в группах

Приносим извинения, если об этом спрашивали раньше, но я не смог найти ни одного вопроса, который бы на это точно отвечал. У меня есть такие данные:

Project        Date   price
      A   30/3/2013    2082
      B   19/3/2013    1567
      B   22/2/2013    1642
      C   12/4/2013    1575
      C    5/6/2013    1582

Я хочу иметь столбец с ценами последней инстанции по группам. Например, для строки 2 цена последнего экземпляра для той же группы будет 1642. Окончательные данные будут выглядеть примерно так:

Project        Date   price   lastPrice
      A   30/3/2013    2082           0
      B   19/3/2013    1567        1642
      B   22/2/2013    1642           0 
      C   12/4/2013    1575           0
      C    5/6/2013    1582        1575

Как это сделать? Основная проблема, с которой я столкнулся, заключается в том, что данные не могут быть упорядочены по дате, поэтому я не могу просто взять последнюю ячейку.


person UD1989    schedule 08.07.2015    source источник
comment
Есть ли причина не переупорядочивать массив по дате, запускать вашу функцию, а затем при желании изменить порядок?   -  person Carl Witthoft    schedule 08.07.2015


Ответы (1)


Вот вариант. Я также рекомендую использовать NAs вместо 0, потому что 0 может быть фактической ценой.

library(dplyr)
df %>% 
  arrange(as.Date(Date, format = "%d/%m/%Y")) %>%
  group_by(Project) %>%
  mutate(lastPrice = lag(price))

# Source: local data frame [5 x 4]
# Groups: Project
# 
#   Project      Date price lastPrice
# 1       B 22/2/2013  1642        NA
# 2       B 19/3/2013  1567      1642
# 3       A 30/3/2013  2082        NA
# 4       C 12/4/2013  1575        NA
# 5       C  5/6/2013  1582      1575

Другой вариант - использовать shift из разрабатываемой версии data.table

library(data.table) ## v >= 1.9.5
setDT(df)[order(as.Date(Date, format = "%d/%m/%Y")), 
                lastPrice := shift(price), 
                by = Project]

#    Project      Date price lastPrice
# 1:       A 30/3/2013  2082        NA
# 2:       B 19/3/2013  1567      1642
# 3:       B 22/2/2013  1642        NA
# 4:       C 12/4/2013  1575        NA
# 5:       C  5/6/2013  1582      1575

Или с базой R

df <- df[order(df$Project, as.Date(df$Date, format = "%d/%m/%Y")), ]
within(df, lastPrice <- ave(price, Project, FUN = function(x) c(NA, x[-length(x)])))
#   Project      Date price lastPrice
# 1       A 30/3/2013  2082        NA
# 3       B 22/2/2013  1642        NA
# 2       B 19/3/2013  1567      1642
# 4       C 12/4/2013  1575        NA
# 5       C  5/6/2013  1582      1575

В качестве примечания, лучше сохранить столбец даты в классе Date в первую очередь, поэтому я бы рекомендовал сделать df$Date <- as.Date(df$Date, format = "%d/%m/%Y") раз и навсегда.

person David Arenburg    schedule 08.07.2015
comment
Жаль, что я не могу дать отдельный +1 за ответ и еще один за отличный совет по установке дат для класса Date. - person Carl Witthoft; 08.07.2015