根据以前的行更新数据框行

时间:2017-04-19 21:25:04

标签: r

给出下面的数据框(按时间排序的简单时间序列):

 time groups      value     value1
1    1      b -0.6264538  0.7383247
2    2      b  0.1836433  0.5757814
3    3      b -0.8356286 -0.3053884
4    1      a  1.5952808  1.5117812
5    2      a  0.3295078  0.3898432
6    3      a -0.8204684 -0.6212406
7    4      a  0.4874291 -2.2146999

对于每个组(a或b)以及该组中的每一行(在时间t),我想将每一行更新为当前行(在时间t)和前一行的缩放版本之和(在时间t-1)(如果前一行不存在,则不更新)

棘手的部分是,一旦一行得到更新,更新版本(而不是原始版本)应该用于更新下一行。我可以通过循环时间和组来实现这一点。我想知道是否有更有效的方法来使用lag()/ dplyr /...?

set.seed(1)
data <- data.frame(time = c(1:3, 1:4),
                   groups = c(rep(c("b", "a"), c(3, 4))),
                   value = rnorm(7), value1=rnorm(7))

alfa = 0.1
for (id in unique(data$groups)){
  data_tmp <- data[data$groups==id,]
  for (i in 2:nrow(data_tmp)){
    for (col in colnames(data)[-(1:2)]){
      data[data$groups==id,][i,][col] = data[data$groups==id,][i,][col] + alfa* data[data$groups==id,][i-1,][col]
    }
  }
}

期望的输出:

 time groups      value     value1
1    1      b -0.6264538  0.7383247
2    2      b  0.1209979  0.6496138
3    3      b -0.8235288 -0.2404270
4    1      a  1.5952808  1.5117812
5    2      a  0.4890359  0.5410214
6    3      a -0.7715648 -0.5671384
7    4      a  0.4102726 -2.2714137

2 个答案:

答案 0 :(得分:2)

你所要求的基本上是一个指数加权的移动总和。有一些软件包提供了支持这个概念的功能,但这里有一个我用过的快速功能:

EWS <- function(x, alfa = 0.1) sum(x * (alfa ^ (length(x):1 - 1)))
EWMS <- function(x, width, FUN, ...) {
  FUN <- match.fun(FUN)
  lenx <- length(x)
  for (i in tail(seq_along(x), n = 1-width)) {
    x[i] <- do.call(FUN, c(list(x[ max(1, i-width+1):i ]), list(...)))
  }
  x
}

EWS可以简单地更改为使用mean或其他向量函数。)

简单的概念证明。 1:3的EWS(alfa为0.1)应为

3*(10^0) + 2*(10^1) + 1*(10^2)
3*(1) + 2*(0.1) + 1*(0.01)
### R-ified/simplified to
3:1 * 10^-(0:2)
# [1] 3.00 0.20 0.01
sum(3:1 * 10^-(0:2))
# [1] 3.21
EWS(1:3, alfa=0.1)
# [1] 3.21

假设“3”是最新数据,“2”和“1”是过去。 (这很容易改变,这只是一个起点。)

移动部分同样合理。我发现电子表格是一种直接的方式来演示应该正在发生什么:

screenshot of excel formulas

EWMS(1:5, width=2, EWS)
# [1] 1.0000 2.1000 3.2100 4.3210 5.4321
EWMS(1:5, width=3, EWS)
# [1] 1.0000 2.1000 3.2200 4.3430 5.4665

因此将其改编为@ PLapointe的dplyr推荐:

library(dplyr)
dat %>%
  group_by(groups) %>%
  mutate_each(funs(EWMS(., width=2, EWS)), -time) %>%
  ungroup()
# # A tibble: 7 × 4
#    time groups      value     value1
#   <int>  <chr>      <dbl>      <dbl>
# 1     1      b -0.6264538  0.7383247
# 2     2      b  0.1209979  0.6496139
# 3     3      b -0.8235288 -0.2404270
# 4     1      a  1.5952808  1.5117812
# 5     2      a  0.4890359  0.5410213
# 6     3      a -0.7715648 -0.5671385
# 7     4      a  0.4102726 -2.2714137

答案 1 :(得分:1)

以下是dplyr

的方法
df1<-read.table(text="time groups      value     value1
1    1      b -0.6264538  0.7383247
2    2      b  0.1836433  0.5757814
3    3      b -0.8356286 -0.3053884
4    1      a  1.5952808  1.5117812
5    2      a  0.3295078  0.3898432
6    3      a -0.8204684 -0.6212406
7    4      a  0.4874291 -2.2146999",header=TRUE, stringsAsFactors=FALSE)


alfa  <- 0.1
func <-function(x){x+alfa*dplyr::lag(x,default = 0)}

library(dplyr)
df1 %>%
group_by(groups) %>%
mutate_each(funs(func(.)),-time)

   time groups      value     value1
  <int>  <chr>      <dbl>      <dbl>
1     1      b -0.6264538  0.7383247
2     2      b  0.1209979  0.6496139
3     3      b -0.8172643 -0.2478103
4     1      a  1.5952808  1.5117812
5     2      a  0.4890359  0.5410213
6     3      a -0.7875176 -0.5822563
7     4      a  0.4053823 -2.2768240