对时间衰减的行(rollapply)求和

时间:2014-11-03 05:45:30

标签: r time sum data.table rollapply

这是我之前发布的问题的后续问题(有关详细信息,请参阅Sum over rows with multiple changing conditions R data.table)。我想计算3个科目在过去5年中经历过一次事件的次数。因此,使用rollapply包中的zoo对滚动窗口进行求和。这假设5年前的经验与1年前的经验一样重要(相同的权重),所以现在我想要为进入总和的经验包括时间衰减。这基本上意味着5年前的经验并没有以与1年前相同的权重进入总和。

我的情况我希望包括一个与年龄相关的衰变(即使对于其他应用程序,可能有更快或更慢的衰变,例如平方根或正方形)。

例如,假设我有以下数据(为了清楚起见,我建立在先前的数据上):

mydf <- data.frame (Year = c(2000, 2001, 2002, 2004, 2005,
                         2007, 2000, 2001, 2002, 2003,
                         2003, 2004, 2005, 2006, 2006, 2007),
                Name = c("Tom", "Tom", "Tom", "Fred", "Gill",
                         "Fred", "Gill", "Gill", "Tom", "Tom",
                         "Fred", "Fred", "Gill", "Fred", "Gill", "Gill"))

# Create an indicator for the experience 
mydf$Ind <- 1

# Load require packages
library(data.table)
library(zoo)

# Set data.table
setDT(mydf)
setkey(mydf, Name,Year)

# Perform cartesian join to calculate experience. I2 is the new experience indicator 
m <- mydf[CJ(unique(Name),seq(min(Year)-5, max(Year))),allow.cartesian=TRUE][,
        list(Ind = unique(Ind), I2 = sum(Ind,na.rm=TRUE)),
        keyby=list(Name,Year)]

# This is the approach I have been taking so far. Note that is a simple rolling sum of I2
m[,Exp := rollapply(I2, 5, function(x) sum(head(x,-1)), 
                align = 'right', fill=0),by=Name]

现在的问题是,如何在此计算中包含与年龄相关的衰减。为了对此进行建模,我需要根据经验的年龄将经验划分为总和。

我一直在尝试使用这些方面的东西来实现它:

 m[,Exp_age := rollapply(I2, 5, function(x) sum(head(x,-1)/(tail((Year))-head(Year,-1))), 
                     align = 'right', fill=0),by=Name]

但它不起作用。我认为我的主要问题是我无法获得正确的年龄,所以我可以除以总和的年龄。结果应类似于Exp_age myres下面的data.frame

myres <- data.frame(Name = c("Fred", "Fred", "Fred", "Fred", "Fred", 
                         "Gill", "Gill", "Gill", "Gill", "Gill", "Gill", 
                         "Tom", "Tom", "Tom", "Tom", "Tom"), 
                Year = c(2003, 2004, 2004, 2006, 2007, 2000, 2001, 2005,
                         2005, 2006, 2007, 2000, 2001, 2002, 2002, 2003), 
                Ind = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), 
                Exp = c(0, 1, 1, 3, 4, 0, 1, 1, 1, 2, 3, 0, 1, 2, 2, 4), 
                Exp_age = c(0, 1, 1, 1.333333333, 1.916666667, 0, 1, 0.45, 
                            0.45, 2.2, 2, 0, 1, 1.5, 1.5, 2.833333333))

任何指针都将非常感谢!

1 个答案:

答案 0 :(得分:2)

如果我理解正确,您正尝试使用rollapply进行width=5,而不是做一个简单的总和,您想要加权总和。权重是相对于5年窗口的体验年龄。我会这样做:首先在data.table中设置密钥,使其按Name正确递增,然后您知道x变量中的最后一项是最年轻的第一项是最早的(您已在代码中执行此操作)。我不知道你想要哪个方向的重量(最小的是最重的或最老的)但是你明白了这一点:

setkey(m, Name, Year)
my_fun = function(x) { w = 1:length(x); sum(x*w)}
m[,Exp_age:=rollapply(I2, width=5, by=1, fill=NA, FUN=my_fun, by.column=FALSE, align="right") ,by=Name]