6

我不需要经常使用 R 中的日期,但我想这相当容易。我有如下几年的每日数据,其中包含一些值,我想在每 8 天期间获取相关值的总和。最好的方法是什么?

您能提供的任何帮助将不胜感激!

 str(temp)
'data.frame':648 obs. of  2 variables:
 $ Date : Factor w/ 648 levels "2001-03-24","2001-03-25",..: 1 2 3 4 5 6 7 8 9 10 ...
 $ conv2: num  -3.93 -6.44 -5.48 -6.09 -7.46 ...

head(temp)
Date              amount
24/03/2001  -3.927020472
25/03/2001  -6.4427004
26/03/2001  -5.477592528
27/03/2001  -6.09462162
28/03/2001  -7.45666902
29/03/2001  -6.731540928
30/03/2001  -6.855206184
31/03/2001  -6.807210228
1/04/2001   -5.40278802

我尝试使用聚合函数,但由于某些原因它不起作用并且聚合方式错误:

z <- aggregate(amount ~ Date, timeSequence(from =as.Date("2001-03-24"),to =as.Date("2001-03-29"), by="day"),data=temp,FUN=sum)
4

5 回答 5

6

我更喜欢xts这种操作的包。

  1. 我读了你的数据,作为动物园对象。查看格式选项的灵活性。

    library(xts)
    ts.dat <- read.zoo(text ='Date              amount
    24/03/2001  -3.927020472
    25/03/2001  -6.4427004
    26/03/2001  -5.477592528
    27/03/2001  -6.09462162
    28/03/2001  -7.45666902
    29/03/2001  -6.731540928
    30/03/2001  -6.855206184
    31/03/2001  -6.807210228
    1/04/2001   -5.40278802',header=TRUE,format = '%d/%m/%Y')
    
  2. 然后我提取给定时期的索引

    ep <- endpoints(ts.dat,'days',k=8)
    
  3. 最后,我将我的函数应用于每个索引的时间序列。

    period.apply(x=ts.dat,ep,FUN=sum )
    2001-03-29 2001-04-01 
    -36.13014  -19.06520 
    
于 2013-01-07T08:15:44.570 回答
5

cut()在您的aggregate()命令中使用。

一些样本数据:

set.seed(1)
mydf <- data.frame(
    DATE = seq(as.Date("2000/1/1"), by="day", length.out = 365),
    VALS = runif(365, -5, 5))

现在,聚合。详情请参阅?cut.Date。您可以使用以下命令指定每个组中所需的天数cut

output <- aggregate(VALS ~ cut(DATE, "8 days"), mydf, sum)
list(head(output), tail(output))
# [[1]]
#   cut(DATE, "8 days")      VALS
# 1          2000-01-01  8.242384
# 2          2000-01-09 -5.879011
# 3          2000-01-17  7.910816
# 4          2000-01-25 -6.592012
# 5          2000-02-02  2.127678
# 6          2000-02-10  6.236126
# 
# [[2]]
#    cut(DATE, "8 days")       VALS
# 41          2000-11-16 17.8199285
# 42          2000-11-24 -0.3772209
# 43          2000-12-02  2.4406024
# 44          2000-12-10 -7.6894484
# 45          2000-12-18  7.5528077
# 46          2000-12-26 -3.5631950
于 2013-01-07T06:53:20.420 回答
2

滚动应用。zoo 包有一个滚动应用功能,它也可以进行非滚动聚合。首先temp使用如下方式将数据框转换为动物园read.zoo

library(zoo)
zz <- read.zoo(temp)

然后它只是:

rollapply(zz, 8, sum, by = 8)

by = 8如果您想要滚动总计,请 删除。

(请注意,temp您问题中的两个版本不一样。它们具有不同的列标题,并且 Date 列采用不同的格式。我在str(temp)这里假设了输出版本。对于head(temp)版本,必须向 . 添加format = "%d/%m/%Y"参数read.zoo。)

聚合。这是一个不使用任何外部包的解决方案。它aggregate基于原始数据框使用。

ix <- 8 * ((1:nrow(temp) - 1) %/% 8 + 1)
aggregate(temp[2], list(period = temp[ix, 1]), sum)

请注意,ix看起来像这样:

> ix
[1]  8  8  8  8  8  8  8  8 16

因此它将前 8 行的索引、后 8 行的索引分组,依此类推。

于 2013-01-07T12:25:31.973 回答
1

这些不是日期分类变量。(没有自尊的程序会显示这样的日期,更不用说这些被标记为因素的事实。)[我后来注意到这些不是同一个对象。]此外,timeSequence 函数(至少在timeDate 包)也不返回 Date 类向量。因此,您期望两个不同的非 Date 对象以合理的方式对齐会有一种“正确的方式”是错误的。具有讽刺意味的是,仅使用 temp$Date 列就可以了,因为:

> z <- aggregate(amount ~ Date, data=temp , FUN=sum)
> z
        Date    amount
1  1/04/2001 -5.402788
2 24/03/2001 -3.927020
3 25/03/2001 -6.442700
4 26/03/2001 -5.477593
5 27/03/2001 -6.094622
6 28/03/2001 -7.456669
7 29/03/2001 -6.731541
8 30/03/2001 -6.855206
9 31/03/2001 -6.807210

但是要以 8 天的间隔获取它,请使用cut.Date

> z <- aggregate(temp$amount , 
                 list(Dts = cut(as.Date(temp$Date, format="%d/%m/%Y"), 
                 breaks="8 day")), FUN=sum)
> z
         Dts          x
1 2001-03-24 -49.792561
2 2001-04-01  -5.402788
于 2013-01-07T06:56:52.710 回答
0

一种更简洁的方法扩展到@G。格洛腾迪克方法。注意:不考虑日期是连续的还是不连续的,总和是根据固定的宽度计算的。


代码

  interval = 8 # your desired date interval. 2 days, 3 days or whatevea 
  enddate = interval-1 # this sets the enddate
  nrows = nrow(z)
  z <- aggregate(.~V1,data = df,sum) # aggregate sum of all duplicate dates
  z$V1 <- as.Date(z$V1)
  data.frame ( Start.date = (z[seq(1, nrows, interval),1]),
               End.date =  z[seq(1, nrows, interval)+enddate,1],
               Total.sum = rollapply(z$V2, interval, sum, by = interval, partial = TRUE))

输出

   Start.date   End.date   Total.sum
1  2000-01-01 2000-01-08   9.1395926
2  2000-01-09 2000-01-16  15.0343960
3  2000-01-17 2000-01-24   4.0974712
4  2000-01-25 2000-02-01   4.1102645
5  2000-02-02 2000-02-09 -11.5816277

数据

  df <- data.frame(
  V1 = seq(as.Date("2000/1/1"), by="day", length.out = 365),
  V2 = runif(365, -5, 5))
于 2017-02-04T00:10:19.103 回答