【问题标题】:R. n Previous Elements in a data frame of another columnR. n 另一列数据框中的先前元素
【发布时间】:2023-03-28 03:51:01
【问题描述】:

我想添加一个新列,其中包含来自另一列的前 n 个元素的向量(或列表)。分组后进行计算。

这是一个 n=2 的示例。输入:

v0 = c(rep("a",5),rep("b",5))
v1 = 1:10
DF1 <- data.frame(v0,v1)

> DF1
   v0 v1
1   a  1
2   a  2
3   a  3
4   a  4
5   a  5
6   b  6
7   b  7
8   b  8
9   b  9
10  b 10

输出:新列应该是整数向量(或列表)并包含以下值:

> DF2_L
   v0 v1    myL
1   a  1 NA, NA
2   a  2  1, NA
3   a  3   2, 1
4   a  4   3, 2
5   a  5   4, 3
6   b  6   5, 4
7   b  7   6, 5
8   b  8   7, 6
9   b  9   8, 7
10  b 10   9, 8

一个简单的解决方案是

DF2 <- DF1 %>% group_by(v0) %>% 
  mutate(i1=lag(v1,1), i2=lag(v1,2), 
                      myL = mapply(c, i1, i2, SIMPLIFY = F))%>%
  select(-c(i1,i2))

但是这只是一个简化的表格。对于我的计算,n 是 36。这意味着我需要为 lag(v1,1)、lag(v1,2) ... lag(v1,36) 创建 36 个新的“虚拟”列,并将它们组合成一个列表。这不方便。它必须是另一种方式。

我想使用 rollapply。使用 F = list 但我收到错误消息

t <- DF1 %>% group_by(v0) %>% 
  mutate( myL= rollapply(lag(v1),
                         2, fill=NA, align="right",
                         list))

Error: Problem with `mutate()` input `myL`.
x “x” : attempt to define invalid zoo object
i Input `myL` is `rollapply(lag(v1), 2, fill = NA, align = "right", list)`.
i The error occurred in group 1: v0 = "a".
Run `rlang::last_error()` to see where the error occurred.

当我使用 FUN = c.我将每个元素作为一个单独的列

t <- DF1 %>% group_by(v0) %>% 
  mutate( myL= rollapply(lag(v1),
                         2, fill=NA, align="right",
                         c))

   v0       v1 myL[,1]  [,2]
   <fct> <int>   <int> <int>
 1 a         1      NA    NA
 2 a         2      NA     1
 3 a         3       1     2
 4 a         4       2     3
 5 a         5       3     4
 6 b         6      NA    NA
 7 b         7      NA     6
 8 b         8       6     7
 9 b         9       7     8
10 b        10       8     9

【问题讨论】:

    标签: r dataframe analytics lag rolling-computation


    【解决方案1】:

    首先请注意,问题中的t 没有将这两个元素放在t 的单独列中。 t 有 3 列,不是 4 列,但第 3 列是矩阵。

    dim(t)
    ## [1] 10  3
    
    dim(t[[3]])
    ## [1] 10  2
    

    滚动应用

    要获得一个整数向量列表的列,使用c 运行rollapply,然后将结果矩阵拆分为一个列表:

    library(dplyr)
    library(zoo)
    
    k <- 2
    out <- DF1 %>%
      group_by(v0) %>%
      mutate(v2 = rollapply(c(rep(NA, k), v1), list(-seq(k)), c) %>%
                  split(1:n()) %>%
                  unname) %>%
      ungroup
    
    str(out)
    

    给予:

    tibble [10 x 3] (S3: tbl_df/tbl/data.frame)
     $ v0: chr [1:10] "a" "a" "a" "a" ...
     $ v1: int [1:10] 1 2 3 4 5 6 7 8 9 10
     $ v2:List of 10
      ..$ : int [1:2] NA NA
      ..$ : int [1:2] 1 NA
      ..$ : int [1:2] 2 1
      ..$ : int [1:2] 3 2
      ..$ : int [1:2] 4 3
      ..$ : int [1:2] NA NA
      ..$ : int [1:2] 6 NA
      ..$ : int [1:2] 7 6
      ..$ : int [1:2] 8 7
      ..$ : int [1:2] 9 8
    

    lag.zoo

    类似的方法是转换为 zoo 并使用lag.zoo。它可以处理多个滞后。之后我们使用coredata 将动物园转换回矩阵。

    请注意,dplyr 会覆盖基本的 lag 泛型,这会禁用其他包中的所有 lag 方法,因此请确保在加载 dplyr 时排除 dplyr 的 lag。如下面的代码所示。 dplyr 的 lag 仍然可以在需要时使用 dplyr::lag 。交替使用下面的stats::lag 以确保调度lag.zoo

    结果与上面rollapply 的结果相同。

    library(dplyr, exclude = "lag")  # important!
    library(zoo)
    
    k <- 2
    out <- DF1 %>%
      group_by(v0) %>%
      mutate(v2 = lag(zoo(c(rep(NA, k-1), v1)), -seq(2)) %>%
                  coredata %>%
                  split(1:n()) %>%
                  unname) %>%
      ungroup 
    

    toString

    另一种可能性(不等效)是使用toString 创建一个字符串列。每个单元格都是一个字符串(不是字符向量)。

    k <- 2
    DF1 %>%
      group_by(v0) %>%
      mutate(v2 = rollapply(c(rep(NA, k), v1), list(-seq(k)), toString)) %>%
      ungroup
    

    给予:

    # A tibble: 10 x 3
       v0       v1 v2    
       <chr> <int> <chr> 
     1 a         1 NA, NA
     2 a         2 1, NA 
     3 a         3 2, 1  
     4 a         4 3, 2  
     5 a         5 4, 3  
     6 b         6 NA, NA
     7 b         7 6, NA 
     8 b         8 7, 6  
     9 b         9 8, 7  
    10 b        10 9, 8  
    

    【讨论】:

      【解决方案2】:

      这符合你想要的吗?

      v0 = c(rep("a",5),rep("b",5))
      v1 = 1:10
      DF1 <- data.frame(v0,v1)
      
      n <- 2
      
      bind_cols(DF1,
                map_dfc(1:n,
                        ~ lag(DF1$v1, .x))) %>%  #simple loop creating lagged columns
        group_by(v0, v1) %>%   # the variables we don't want to include
        nest() %>%
        mutate(my_list = list(set_names(unlist(data), NULL))) #make each tibble into an unnamed vector
      # A tibble: 10 x 4
      # Groups:   v0, v1 [10]
      #   v0       v1 data             my_list  
      #   <chr> <int> <list>           <list>   
      # 1 a         1 <tibble [1 x 2]> <int [2]>
      # 2 a         2 <tibble [1 x 2]> <int [2]>
      # 3 a         3 <tibble [1 x 2]> <int [2]>
      # 4 a         4 <tibble [1 x 2]> <int [2]>
      # 5 a         5 <tibble [1 x 2]> <int [2]>
      # 6 b         6 <tibble [1 x 2]> <int [2]>
      # 7 b         7 <tibble [1 x 2]> <int [2]>
      # 8 b         8 <tibble [1 x 2]> <int [2]>
      # 9 b         9 <tibble [1 x 2]> <int [2]>
      #10 b        10 <tibble [1 x 2]> <int [2]>
      
      xx$my_list
      # [[1]]
      # [1] NA NA
      # 
      # [[2]]
      # [1]  1 NA
      # 
      # [[3]]
      # [1] 2 1
      # 
      # [[4]]
      # [1] 3 2
      # 
      # [[5]]
      # [1] 4 3
      # 
      # [[6]]
      # [1] 5 4
      # 
      # [[7]]
      # [1] 6 5
      # 
      # [[8]]
      # [1] 7 6
      # 
      # [[9]]
      # [1] 8 7
      # 
      # [[10]]
      # [1] 9 8
      

      编辑:我实际上不确定你想要什么,如果你只想要串联滞后值的向量,那么这样做会更清楚:

      lagged_cols <- map_dfc(1:n,
                             ~ lag(DF1$v1, .x))
      
      apply(lagged_cols, 1, paste, collapse=" ")
      # [1] "NA NA" "1 NA"  "2 1"   "3 2"   "4 3"   "5 4"   "6 5"   "7 6"   "8 7"  
      # [10] "9 8"  
      

      【讨论】:

        【解决方案3】:

        data.table 解决方案:

        library(data.table)
        setDT(DF1)
        DF1[, myL := sapply(transpose(shift(v1, n=1:2)), toString), by = v0]
        
        #     v0 v1    myL
        #  1:  a  1 NA, NA
        #  2:  a  2  1, NA
        #  3:  a  3   2, 1
        #  4:  a  4   3, 2
        #  5:  a  5   4, 3
        #  6:  b  6 NA, NA
        #  7:  b  7  6, NA
        #  8:  b  8   7, 6
        #  9:  b  9   8, 7
        # 10:  b 10   9, 8
        

        这会产生一个向量列表的列:

        # > sapply(DF1, class)
        #          v0          v1         myL 
        # "character"   "integer"      "list" 
        

        注意事项

        • 可以替换函数c来获取列表列表(list)、字符串列表(toString)等。
        • 如果您不想使用data.table,您可以使用setDF() 将结果转换为data.frame
        • 也可以在一般dplyr 设置中工作:
        DF1 %>% group_by(v0) %>% mutate(myL = lapply(transpose(shift(v1, n=1:2)), c))
        

        【讨论】:

          猜你喜欢
          • 2020-11-05
          • 1970-01-01
          • 2019-03-29
          • 2020-05-28
          • 1970-01-01
          • 1970-01-01
          • 2017-03-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多