将不规则时间序列拆分为常规月平均值 - R.

bik*_*lub 6 sql r zoo xts data.table

为了对能源使用产生季节性影响,我需要将计费数据库中的能源使用信息与月度温度保持一致.

我正在使用具有不同长度和开始日期和结束日期的帐单的结算数据集,并且我想获得每个月内每个帐户的月平均值.例如,我有一个具有以下特征的计费数据库:

   acct amount      begin        end days
1  2242  11349 2009-10-06 2009-11-04   29
2  2242  12252 2009-11-04 2009-12-04   30
3  2242  21774 2009-12-04 2010-01-08   35
4  2242  18293 2010-01-08 2010-02-05   28
5  2243  27217 2009-10-06 2009-11-04   29
6  2243    117 2009-11-04 2009-12-04   30
7  2243  14543 2009-12-04 2010-01-08   35
Run Code Online (Sandbox Code Playgroud)

我想弄清楚如何强制这些有点不规则的时间序列(对于每个帐户)来获得每个月内每个月内的平均金额,以便:

   acct amount      begin        end days avgamtpday
1  2242  11349 2009-10-01 2009-10-31   31          X
2  2242  12252 2009-11-01 2009-11-30   30          X
3  2242  21774 2009-12-01 2010-12-31   31          X
4  2242  18293 2010-01-01 2010-01-31   31          X
4  2242  18293 2010-02-01 2010-02-28   28          X
5  2243  27217 2009-10-01 2009-10-31   31          X
6  2243    117 2009-11-01 2009-11-30   30          X
7  2243  14543 2009-12-01 2009-12-31   30          X
7  2243  14543 2010-01-01 2010-01-31   31          X
Run Code Online (Sandbox Code Playgroud)

我完全不知道哪种工具可以做到这一点,因为我只需要这样做一次.

另外一个皱纹是桌子长约150,000行,这在大多数标准下并不是很大,但是足够大以使R中的循环解决方案变得困难.我已经调查过使用R中的zoo,xts和tempdisagg软件包.我开始编写一个非常丑陋的循环来分割每个帐单,然后在现有帐单中每个月创建一行,然后按应用程序汇总tapply()和几个月,但老实说,看不出如何有效地做到这一点.

在MySQL中,我试过这个:

创建或替换视图v3为select 1 n union all select 1 union all select 1;
创建或替换视图v作为选择1 n从v3 a,v3 b union all select 1;
设为@n = 0;
删除表如果存在日历; 创建表日历(dt日期主键);
插入日历
选择演员阵容('2008-1-1'+区间@n:= @ n + 1天作为日期)作为来自va,vb,vc,vd,ve,v的dt;

select acct,amount,begin,end,billAmtPerDay,sum(billAmtPerDay),MonthAmt,count()天,sum(billAmtPerDay)/ count()AverageAmtPerDay,year(dt),month(dt)FROM(select*,amount/days billAmtPerDay来自账单b内部联接日历c在dt之间的开始和结束之间并开始<> dt)x group by acct,amount,begin,end,billAmtPerDay,year(dt),month(dt);

但由于我不明白的原因,我的服务器不喜欢这个表,并且挂起内连接,即使我进行不同的计算.我正在调查是否有任何临时内存限制.

谢谢!

Mat*_*wle 9

这是一个开始使用data.table:

billdata <- read.table(text=" acct amount begin end days
1 2242 11349 2009-10-06 2009-11-04 29
2 2242 12252 2009-11-04 2009-12-04 30
3 2242 21774 2009-12-04 2010-01-08 35
4 2242 18293 2010-01-08 2010-02-05 28
5 2243 27217 2009-10-06 2009-11-04 29
6 2243 117 2009-11-04 2009-12-04 30
7 2243 14543 2009-12-04 2010-01-08 35", sep=" ", header=TRUE, row.names=1)

require(data.table)
DT = as.data.table(billdata)
Run Code Online (Sandbox Code Playgroud)

首先,更改列的类型beginend日期.与data.frame不同,它不会复制整个数据集.

DT[,begin:=as.Date(begin)]
DT[,end:=as.Date(end)]
Run Code Online (Sandbox Code Playgroud)

然后找出时间跨度,找到每天的现行账单,并汇总.

alldays = DT[,seq(min(begin),max(end),by="day")]

setkey(DT, acct, begin)

DT[CJ(unique(acct),alldays),
   mean(amount/days,na.rm=TRUE),
   by=list(acct,month=format(begin,"%Y-%m")), roll=TRUE]

    acct   month        V1
 1: 2242 2009-10 391.34483
 2: 2242 2009-11 406.69448
 3: 2242 2009-12 601.43226
 4: 2242 2010-01 646.27465
 5: 2242 2010-02 653.32143
 6: 2243 2009-10 938.51724
 7: 2243 2009-11  97.36172
 8: 2243 2009-12 375.68065
 9: 2243 2010-01 415.51429
10: 2243 2010-02 415.51429
Run Code Online (Sandbox Code Playgroud)

我认为你会发现流行的连接逻辑在SQL中非常麻烦,而且速度较慢.

我说这是一个提示,因为它不太正确.注意第10行是重复的,因为帐户2243不像帐户2242那样延伸到2010-02.要完成它,您可以rbind在每个帐户的最后一行使用rolltolast而不是roll.或者也许是alldays通过帐户而不是所有帐户创建的.

看看上面的速度是否可以接受,我们可以从那里开始.

您可能会遇到1.8.2中已修复的1.8.2中的错误.我正在使用v1.8.3.

组合包含缺失组和分组依据的连接时出现"内部"错误消息,#2162.例如:X [Y,.N,by = NonJoinColumn]其中Y包含一些与X不匹配的行.此错误也可能导致seg错误.

让我知道,我们可以解决,或从R-Forge升级到1.8.3.

顺便说一句,很好的示例数据.这使得答案更快.


以上是上面提到的完整答案.我不得不承认这有点棘手,因为它结合了几个特征data.table.这应该在1.8.2中有效,但我只在1.8.3中测试过.

DT[ setkey(DT[,seq(begin[1],last(end),by="day"),by=acct]),
    mean(amount/days,na.rm=TRUE),
    by=list(acct,month=format(begin,"%Y-%m")), roll=TRUE]

   acct   month        V1
1: 2242 2009-10 391.34483
2: 2242 2009-11 406.69448
3: 2242 2009-12 601.43226
4: 2242 2010-01 646.27465
5: 2242 2010-02 653.32143
6: 2243 2009-10 938.51724
7: 2243 2009-11  97.36172
8: 2243 2009-12 375.68065
9: 2243 2010-01 415.51429
Run Code Online (Sandbox Code Playgroud)