使用dplyr计算变量变化的更简单方法?

4

我正在尝试使用dplyr寻找一种更简单的方法来计算数据框中变量(由列表示)的变化。我的示例数据集类似于以下内容:

structure(list(CAR = structure(c(1L, 2L, 3L, 4L, 5L, 6L, 1L, 
2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L, 4L, 5L, 6L), .Label = c("a", 
"b", "c", "d", "e", "f"), class = "factor"), TIME = c(0L, 0L, 
0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L
), VAR = c(20L, 30L, 40L, 50L, 60L, 70L, 30L, 40L, 50L, 60L, 
70L, 80L, 40L, 50L, 60L, 70L, 80L, 90L)), .Names = c("CAR", "TIME", 
"VAR"), class = "data.frame", row.names = c(NA, -18L))

看起来像

   CAR TIME VAR
1    a    0  20
2    b    0  30
3    c    0  40
4    d    0  50
5    e    0  60
6    f    0  70
7    a    1  30
8    b    1  40
9    c    1  50
10   d    1  60
11   e    1  70
12   f    1  80
13   a    2  40
14   b    2  50
15   c    2  60
16   d    2  70
17   e    2  80
18   f    2  90

我将尝试计算在每个 CAR 中,TIME 等于 0 和其他时间(例如 1,2)之间的 VAR 变化。以下是我的操作步骤,似乎比较复杂:首先获取 TIME 等于 0VAR 的值。
library(dplyr)
X <- local_test %>% filter(TIME == 0)  %>% group_by(CAR)  %>% mutate(baseline_VAR = VAR)

X 看起来像什么

Source: local data frame [6 x 4]
Groups: CAR

  CAR TIME VAR baseline_VAR
1   a    0  20           20
2   b    0  30           30
3   c    0  40           40
4   d    0  50           50
5   e    0  60           60
6   f    0  70           70

然后,我使用原始数据框 local_test 进行 left_join 操作。

Y  <- left_join(local_test, X, by = c("CAR"))

Y 看起来像

   CAR TIME.x VAR.x TIME.y VAR.y baseline_VAR
1    a      0    20      0    20           20
2    b      0    30      0    30           30
3    c      0    40      0    40           40
4    d      0    50      0    50           50
5    e      0    60      0    60           60
6    f      0    70      0    70           70
7    a      1    30      0    20           20
8    b      1    40      0    30           30
9    c      1    50      0    40           40
10   d      1    60      0    50           50
11   e      1    70      0    60           60
12   f      1    80      0    70           70
13   a      2    40      0    20           20
14   b      2    50      0    30           30
15   c      2    60      0    40           40
16   d      2    70      0    50           50
17   e      2    80      0    60           60
18   f      2    90      0    70           70

最后,我在Y中添加了一列,用于计算CAR在两个不同的TIME间的VAR变化。
Y %>% group_by(CAR) %>% mutate(change_VAR = VAR.x - baseline_VAR)

最终的 Y 看起来像什么。
Source: local data frame [18 x 7]
Groups: CAR

   CAR TIME.x VAR.x TIME.y VAR.y baseline_VAR change_VAR
1    a      0    20      0    20           20          0
2    b      0    30      0    30           30          0
3    c      0    40      0    40           40          0
4    d      0    50      0    50           50          0
5    e      0    60      0    60           60          0
6    f      0    70      0    70           70          0
7    a      1    30      0    20           20         10
8    b      1    40      0    30           30         10
9    c      1    50      0    40           40         10
10   d      1    60      0    50           50         10
11   e      1    70      0    60           60         10
12   f      1    80      0    70           70         10
13   a      2    40      0    20           20         20
14   b      2    50      0    30           30         20
15   c      2    60      0    40           40         20
16   d      2    70      0    50           50         20
17   e      2    80      0    60           60         20
18   f      2    90      0    70           70         20

这似乎需要增加额外的列,这样做比较繁琐。我需要重复地对大型数据框执行此操作。有没有更简单(一步)的方法来计算change_VAR
谢谢!
2个回答

6

可以通过将“VAR”与按“CAR”分组后的“VAR”的min差异来实现。

local_test %>%
     group_by(CAR) %>%
     mutate(change_VAR= VAR- min(VAR))

如果“TIME”的基础值为0(假设每个组中没有重复的“TIME”),则我们对“VAR”进行子集,然后获取差异。

local_test %>% 
      group_by(CAR) %>%
      mutate(change_VAR= VAR- VAR[TIME==0])

有没有简单的方法可以计算与上一期的变化而不是第一期? - Anton
1
@Anton 不太清楚。也许你想要 VAR - lag(VAR) - akrun
是的,这最终是我所做的,但在使用complete()填充数据集之前,否则如果数据中缺少一个时间段,那么时间长度之间就会有差异。 - Anton
@Anton 请考虑发布一个新问题,这样更清晰明了。 - akrun

3
group_by(DF, CAR) %>%
  arrange(CAR, TIME) %>%
  mutate(change_VAR = VAR-VAR[1]) %>%
  ungroup() %>%
  arrange(TIME, CAR)

我进行了比akrun更多的排列,但我不会假设数据一开始就被正确排序。排列还确保每个组中最早的观察值在位置1。

编辑: 如果您对这种事情感兴趣。以下是我的答案和Akrun答案之间的速度比较。(简而言之,选择Akrun)

microbenchmark(
  akrun1 =  DF %>%
              group_by(CAR) %>%
              mutate(change_VAR= VAR- min(VAR)),
  akrun2 = DF %>% 
             group_by(CAR) %>%
             mutate(change_VAR= VAR- VAR[TIME==0]),
  Benjamin = group_by(DF, CAR) %>%
               arrange(CAR, TIME) %>%
               mutate(change_VAR = VAR-VAR[1]) %>%
               ungroup() %>%
               arrange(TIME, CAR))
unit: microseconds
     expr      min        lq      mean   median        uq      max neval cld
   akrun1  887.360  903.1950  975.6354  930.467  954.5125 3246.223   100  a 
   akrun2  888.240  901.1425  947.5220  913.899  952.7530 3002.536   100  a 
 Benjamin 1584.697 1604.7835 1720.8034 1662.993 1692.1705 3765.561   100   b

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