【问题标题】:R How to lag a dataframe by groupsR如何按组滞后数据框
【发布时间】:2018-12-07 01:22:15
【问题描述】:

我有以下数据集:

Name  Year  VarA  VarB Data.1  Data.2
A     2016  L     H    100     101
A     2017  L     H    105     99
A     2018  L     H    103     105
A     2016  L     A    90      95
A     2017  L     A    99      92
A     2018  L     A    102     101

我想通过分组添加一个滞后变量:Name、VarA、VarB,以便我的数据看起来像:

Name  Year  VarA  VarB Data.1  Data.2  Lg1.Data.1 Lg2.Data.1
A     2016  L     H    100     101     NA        NA
A     2017  L     H    105     99      100       NA
A     2018  L     H    103     105     105       100
A     2016  L     A    90      95      NA        NA
A     2017  L     A    99      92      90        NA
A     2018  L     A    102     101     99        90

我找到了以下链接,这很有帮助:debugging: function to create multiple lags for multiple columns (dplyr)

我正在使用以下代码:

df <- df %>% 
  group_by(Name) %>% 
  arrange(Name, VarA, VarB, Year) %>% 
  do(data.frame(., setNames(shift(.[,c(5:6)], 1:2), c(seq(1:8)))))

但是,滞后抵消了与名称相关的所有数据,而不是我想要的分组,所以只有 2018 年是准确滞后的。

Name  Year  VarA  VarB Data.1  Data.2  Lg1.Data.1 Lg2.Data.1
A     2016  L     H    100     101     NA        NA
A     2017  L     H    105     99      100       NA
A     2018  L     H    103     105     105       100
A     2016  L     A    90      95      103       105
A     2017  L     A    99      92      90        103
A     2018  L     A    102     101     99        90

如何为每个新的分组组合(例如 Name / VarA / VarB)重置滞后?

【问题讨论】:

  • 我想你会group_by(Name, VarA, VarB) 而不仅仅是group_by(Name)

标签: r dplyr


【解决方案1】:

dplyr::lag 可让您设置要延迟的距离。在创建滞后变量之前,您可以按所需的任何变量(在本例中为 NameVarAVarB)进行分组。

library(dplyr)

df %>%
  group_by(Name, VarA, VarB) %>%
  mutate(Lg1.Data.1 = lag(Data.1, n = 1), Lg2.Data.1 = lag(Data.1, n = 2))
#> # A tibble: 6 x 8
#> # Groups:   Name, VarA, VarB [2]
#>   Name   Year VarA  VarB  Data.1 Data.2 Lg1.Data.1 Lg2.Data.1
#>   <chr> <dbl> <chr> <chr>  <dbl>  <dbl>      <dbl>      <dbl>
#> 1 A      2016 L     H        100    101         NA         NA
#> 2 A      2017 L     H        105     99        100         NA
#> 3 A      2018 L     H        103    105        105        100
#> 4 A      2016 L     A         90     95         NA         NA
#> 5 A      2017 L     A         99     92         90         NA
#> 6 A      2018 L     A        102    101         99         90

如果您想要一个可以扩展到更多滞后的版本,您可以使用一些non-standard evaluation 来动态创建新的滞后列。我将使用purrr::map 来迭代一组n 以滞后,制作一个添加了新列的数据框列表,然后将所有数据框连接在一起。可能有更好的 NSE 方法来做到这一点,所以希望有人可以改进它。

我正在编造一些新数据,只是为了说明更广泛的年份。在mutate 中,您可以使用quo_name 创建列名。

library(dplyr)
library(purrr)

set.seed(127)
df <- tibble(
  Name = "A", Year = rep(2016:2020, 2), VarA = "L", VarB = rep(c("H", "A"), each = 5),
  Data.1 = sample(1:10, 10, replace = T), Data.2 = sample(1:10, 10, replace = T) 
)

df_list <- purrr::map(1:4, function(i) {
  df %>%
    group_by(Name, VarA, VarB) %>%
    mutate(!!quo_name(paste0("Lag", i)) := dplyr::lag(Data.1, n = i))
})

您无需保存此列表——我只是为了展示其中一个数据框的示例。你可以直接进入reduce

df_list[[3]]
#> # A tibble: 10 x 7
#> # Groups:   Name, VarA, VarB [2]
#>    Name   Year VarA  VarB  Data.1 Data.2  Lag3
#>    <chr> <int> <chr> <chr>  <int>  <int> <int>
#>  1 A      2016 L     H          3      9    NA
#>  2 A      2017 L     H          1      4    NA
#>  3 A      2018 L     H          3      8    NA
#>  4 A      2019 L     H          2      2     3
#>  5 A      2020 L     H          4      5     1
#>  6 A      2016 L     A          8      4    NA
#>  7 A      2017 L     A          6      8    NA
#>  8 A      2018 L     A          3      2    NA
#>  9 A      2019 L     A          8      6     8
#> 10 A      2020 L     A          9      1     6

然后使用purrr::reduce 连接列表中的所有数据框。由于每个数据框中都有相同的列,并且这些列是您想要加入的列,因此您可以避免在 inner_join 中指定加入列。

reduce(df_list, inner_join)
#> Joining, by = c("Name", "Year", "VarA", "VarB", "Data.1", "Data.2")
#> Joining, by = c("Name", "Year", "VarA", "VarB", "Data.1", "Data.2")
#> Joining, by = c("Name", "Year", "VarA", "VarB", "Data.1", "Data.2")
#> # A tibble: 10 x 10
#> # Groups:   Name, VarA, VarB [?]
#>    Name   Year VarA  VarB  Data.1 Data.2  Lag1  Lag2  Lag3  Lag4
#>    <chr> <int> <chr> <chr>  <int>  <int> <int> <int> <int> <int>
#>  1 A      2016 L     H          3      9    NA    NA    NA    NA
#>  2 A      2017 L     H          1      4     3    NA    NA    NA
#>  3 A      2018 L     H          3      8     1     3    NA    NA
#>  4 A      2019 L     H          2      2     3     1     3    NA
#>  5 A      2020 L     H          4      5     2     3     1     3
#>  6 A      2016 L     A          8      4    NA    NA    NA    NA
#>  7 A      2017 L     A          6      8     8    NA    NA    NA
#>  8 A      2018 L     A          3      2     6     8    NA    NA
#>  9 A      2019 L     A          8      6     3     6     8    NA
#> 10 A      2020 L     A          9      1     8     3     6     8

reprex package (v0.2.1) 于 2018 年 12 月 7 日创建

【讨论】:

  • 即将发布 df %&gt;% group_by(Name, VarA, VarB) %&gt;% mutate_at(vars(starts_with("Data")), funs(Lg = lag(.))) 。 imo 更健壮。
  • 感谢罗纳克和卡米尔。两种解决方案都解决了我的问题。 Ronak - 有没有比只运行代码多次以获得多年更优雅的方法?
猜你喜欢
  • 2012-04-16
  • 1970-01-01
  • 1970-01-01
  • 2021-04-21
  • 2019-09-05
  • 1970-01-01
  • 1970-01-01
  • 2010-12-11
  • 2018-05-07
相关资源
最近更新 更多