按月/年间隔聚合每日数据

66

我很少在R中使用日期,但我想这应该相当容易。我有一个dataframe中表示日期的列。我只想使用日期创建一个新的dataframe,按月/年汇总第二列。最佳方法是什么?

我想要一个第二个dataframe,以便将其提供给plot。

非常感谢你能提供的任何帮助!

编辑:供参考:

> 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

@Bibert3,你能告诉我们你的日期格式是什么吗?POSIX?字符? - Brandon Bertelsen
9个回答

59

我会使用lubridateplyr库,将日期向下舍入到最接近的月份,使其更容易绘制:

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))

5
如果使用dplyr,最后一行将是 summarise(df, x = mean(my)) - Fato39
如果您想对一个包含多列的数据框进行操作,可以使用以下代码: plyr::ddply(df, "my", numcolwise(mean)) - Raha

43

也许有更优雅的解决方案,但是使用 strftime() 拆分为月份和年份,然后使用 aggregate() 进行聚合就可以了。然后重新组装日期进行绘图。

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 = "-"))

21

我来晚了,但另一个选项是使用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

正如您所看到的,这将以您系统语言(在我的情况下是荷兰语)显示月份名称。


或者使用 lubridatedplyr 的组合:

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))

9
您可以这样做:
short.date = strftime(temp$date, "%Y/%m")
aggr.stat = aggregate(temp$amount ~ short.date, FUN = sum)

short.date 部分非常实用。感谢 @Galina-Alperovich 的好建议! - Michel Mesquita

8
只需使用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是一个函数,可以用于聚合数据(例如求和)


1
为什么要单独回答?在我看来,将其作为您先前答案的替代方案会更好。 - Jaap

5

以下是 dplyr 的一个选项:

library(dplyr)

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

4
我有一个名为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 等方法即可。

1

另外一种解决方案:

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

如果要绘制图表,您可以使用barplot

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

1
此外,鉴于您的时间序列似乎是以xts格式呈现的,您可以使用mean函数将每日时间序列聚合为月度时间序列,如下所示:
d2m <- function(x) {
  aggregate(x, format(as.Date(zoo::index(x)), "%Y-%m"), FUN=mean)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接