Агрегирование ежедневных данных с интервалами в месяц / год

#datetime #r

#datetime #r

Вопрос:

Мне не часто приходится работать с датами в R, но я полагаю, что это довольно просто. У меня есть столбец, который представляет дату во фрейме данных. Я просто хочу создать новый фрейм данных, который суммирует 2-й столбец по месяцам / годам, используя дату. Каков наилучший подход?

Мне нужен второй фрейм данных, чтобы я мог передать его на график.

Мы будем признательны за любую помощь, которую вы можете предоставить!

РЕДАКТИРОВАТЬ: для справки:

 > str(temp)
'data.frame':   215746 obs. of  2 variables:
 $ date  : POSIXct, format: "2011-02-01" "2011-02-01" "2011-02-01" ...
 $ amount: num  1.67 83.55 24.4 21.99 98.88 ...

> head(temp)
        date amount
1 2011-02-01  1.670
2 2011-02-01 83.550
3 2011-02-01 24.400
4 2011-02-01 21.990
5 2011-02-03 98.882
6 2011-02-03 24.900
  

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

1. @Bibert3 не могли бы вы сказать нам, в каком формате ваши даты? POSIX? символ?

Ответ №1:

Я бы сделал это с помощью lubridate и plyr , округляя даты до ближайшего месяца, чтобы упростить их построение:

 library(lubridate)
df <- data.frame(
  date = today()   days(1:300),
  x = runif(300)
)
df$my <- floor_date(df$date, "month")

library(plyr)
ddply(df, "my", summarise, x = mean(x))
  

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

1. Или с помощью dplyr последняя строка будет summarise(df, x = mean(my)) .

2. и если вы хотите создать фрейм данных с несколькими столбцами, подобными этому : plyr::ddply(df, "my", numcolwise(mean))

Ответ №2:

Вероятно, есть более элегантное решение, но разделение на месяцы и годы с помощью strftime() а затем aggregate() ing должно сделать это. Затем повторно соберите дату для построения графика.

 x <- as.POSIXct(c("2011-02-01", "2011-02-01", "2011-02-01"))
mo <- strftime(x, "%m")
yr <- strftime(x, "%Y")
amt <- runif(3)
dd <- data.frame(mo, yr, amt)

dd.agg <- aggregate(amt ~ mo   yr, dd, FUN = sum)
dd.agg$date <- as.POSIXct(paste(dd.agg$yr, dd.agg$mo, "01", sep = "-"))
  

Ответ №3:

Немного поздновато для игры, но другим вариантом было бы использовать data.table :

 library(data.table)
setDT(temp)[, .(mn_amt = mean(amount)), by = .(yr = year(date), mon = months(date))]

# or if you want to apply the 'mean' function to several columns:
# setDT(temp)[, lapply(.SD, mean), by=.(year(date), month(date))]
  

это дает:

      yr      mon mn_amt
1: 2011 februari 42.610
2: 2011    maart 23.195
3: 2011    april 61.891
  

Если вам нужны имена вместо цифр для месяцев, вы можете использовать:

 setDT(temp)[, date := as.IDate(date)
            ][, .(mn_amt = mean(amount)), by = .(yr = year(date), mon = months(date))]
  

это дает:

      yr      mon mn_amt
1: 2011 februari 42.610
2: 2011    maart 23.195
3: 2011    april 61.891
  

Как вы видите, это даст названия месяцев на вашем системном языке (в моем случае это голландский).


Или используя комбинацию lubridate и dplyr :

 temp %>% 
  group_by(yr = year(date), mon = month(date)) %>% 
  summarise(mn_amt = mean(amount))
  

Использованные данные:

 # example data (modified the OP's data a bit)
temp <- structure(list(date = structure(1:6, .Label = c("2011-02-01", "2011-02-02", "2011-03-03", "2011-03-04", "2011-04-05", "2011-04-06"), class = "factor"), 
                       amount = c(1.67, 83.55, 24.4, 21.99, 98.882, 24.9)), 
                  .Names = c("date", "amount"), class = c("data.frame"), row.names = c(NA, -6L))
  

Ответ №4:

Вы можете сделать это как:

 short.date = strftime(temp$date, "%Y/%m")
aggr.stat = aggregate(temp$amount ~ short.date, FUN = sum)
  

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

1. Часть с short.date была очень практичной. Спасибо, @Galina-Alperovich за приятное предложение!

Ответ №5:

Для этого просто используйте пакет xts.

 library(xts)
ts <- xts(temp$amount, as.Date(temp$date, "%Y-%m-%d"))

# convert daily data
ts_m = apply.monthly(ts, FUN)
ts_y = apply.yearly(ts, FUN)
ts_q = apply.quarterly(ts, FUN)
  

где FUN — это функция, с помощью которой вы агрегируете данные (например, sum)

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

1. почему отдельный ответ? лучше добавить это в качестве альтернативы вашему предыдущему ответу, imo

Ответ №6:

Вот dplyr вариант:

 library(dplyr)

df %>% 
  mutate(date = as.Date(date)) %>% 
  mutate(ym = format(date, '%Y-%m')) %>% 
  group_by(ym) %>% 
  summarize(ym_mean = mean(x))
  

Ответ №7:

У меня есть функция monyr , которую я использую для такого рода вещей:

 monyr <- function(x)
{
    x <- as.POSIXlt(x)
    x$mday <- 1
    as.Date(x)
}

n <- as.Date(1:500, "1970-01-01")
nn <- monyr(n)
  

Вы можете изменить as.Date в конце на as.POSIXct , чтобы соответствовать формату даты в ваших данных. Подведение итогов по месяцам — это просто вопрос использования aggregate / by / etc.

Ответ №8:

Еще одно решение:

  rowsum(temp$amount, format(temp$date,"%Y-%m"))
  

Для построения графика вы могли бы использовать barplot :

 barplot(t(rowsum(temp$amount, format(temp$date,"%Y-%m"))), las=2)
  

Ответ №9:

Кроме того, учитывая, что ваши временные ряды, похоже, представлены в формате xts, вы можете агрегировать свои ежедневные временные ряды в месячные временные ряды, используя функцию mean, подобную этой:

 d2m <- function(x) {
  aggregate(x, format(as.Date(zoo::index(x)), "%Y-%m"), FUN=mean)
}