【问题标题】:How to add calculated columns to nested data frames (list columns) using purrr如何使用 purrr 将计算列添加到嵌套数据框(列表列)
【发布时间】:2018-03-08 05:55:54
【问题描述】:

我想对嵌套数据框(存储为列表列)执行计算,并使用 purrr 函数将计算后的变量添加回每个数据框。我将使用此结果连接到其他数据,并保持其紧凑有助于我更好地组织和检查它。我可以通过几个步骤来做到这一点,但似乎有一个我没有遇到过的解决方案。如果有解决方案,我一直无法轻易找到。

加载库。示例需要以下软件包(在 CRAN 上可用):

library(dplyr)
library(purrr)
library(RcppRoll) # to calculate rolling mean

示例数据包含 3 个受试者,并随着时间的推移重复测量:

test <- data_frame(
  id= rep(1:3, each=20),
  time = rep(1:20, 3),
  var1 = rnorm(60, mean=10, sd=3),
  var2 = rnorm(60, mean=95, sd=5)
  )

将数据存储为嵌套数据框

t_nest <- test %>% nest(-id)

     id              data
  <int>            <list>
1     1 <tibble [20 x 3]>
2     2 <tibble [20 x 3]>
3     3 <tibble [20 x 3]>

执行计算。我将根据数据计算多个新变量,尽管稍后可以扩展仅针对一个变量的解决方案。每次计算的结果都会是一个数值向量,与输入的长度相同(n=20):

t1 <- t_nest %>% 
  mutate(var1_rollmean4 = map(data, ~RcppRoll::roll_mean(.$var1, n=4, align="right", fill=NA)),
         var2_delta4 = map(data, ~(.$var2 - lag(.$var2, 3))*0.095),
         var3 = map2(var1_rollmean4, var2_delta4, ~.x -.y))

     id              data var1_rollmean4 var2_delta4       var3
  <int>            <list>         <list>      <list>     <list>
1     1 <tibble [20 x 3]>     <dbl [20]>  <dbl [20]> <dbl [20]>
2     2 <tibble [20 x 3]>     <dbl [20]>  <dbl [20]> <dbl [20]>
3     3 <tibble [20 x 3]>     <dbl [20]>  <dbl [20]> <dbl [20]>

我的解决方案unnest这个数据,然后再nest。这似乎没有什么问题,但似乎可能存在更好的解决方案。

t1 %>% unnest %>% 
  nest(-id)

     id              data
  <int>            <list>
1     1 <tibble [20 x 6]>
2     2 <tibble [20 x 6]>
3     3 <tibble [20 x 6]>

这个其他解决方案 (from SO 42028710) 很接近,但不完全是因为它是一个列表而不是嵌套数据框:

map_df(t_nest$data, ~ mutate(.x, var1calc = .$var1*100))   

我使用purrr Cheatsheet 找到了很多有用的信息,但找不到答案。

【问题讨论】:

    标签: r dplyr purrr


    【解决方案1】:

    您可以在通过 data 列进行映射时包装另一个 mutate,并在每个嵌套的 tibble 中添加列:

    t11 <- t_nest %>% 
        mutate(data = map(data, 
            ~ mutate(.x, 
                var1_rollmean4 = RcppRoll::roll_mean(var1, n=4, align="right", fill=NA),
                var2_delta4 = (var2 - lag(var2, 3))*0.095,
                var3 = var1_rollmean4 - var2_delta4
            )
       ))
    
    t11
    # A tibble: 3 x 2
    #     id              data
    #  <int>            <list>
    #1     1 <tibble [20 x 6]>
    #2     2 <tibble [20 x 6]>
    #3     3 <tibble [20 x 6]>
    

    unnest-nest方法,然后对里面的列重新排序:

    nest_unnest <- t1 %>% 
        unnest %>% nest(-id) %>% 
        mutate(data = map(data, ~ select(.x, time, var1, var2, var1_rollmean4, var2_delta4, var3)))
    
    identical(nest_unnest, t11)
    # [1] TRUE
    

    【讨论】:

      【解决方案2】:

      对于你想要做的事情,嵌套似乎不是必需的

      library(tidyverse)
      library(zoo)
      test %>%
        group_by(id) %>%
        mutate(var1_rollmean4 = rollapplyr(var1, 4, mean, fill=NA),
             var2_delta4 = (var2 - lag(var2, 3))*0.095,
               var3 = (var1_rollmean4 - var2_delta4))
      
      # A tibble: 60 x 7
      # Groups:   id [3]
            # id  time      var1      var2 var1_rollmean4 var2_delta4      var3
         # <int> <int>     <dbl>     <dbl>          <dbl>       <dbl>     <dbl>
       # 1     1     1  9.865199  96.45723             NA          NA        NA
       # 2     1     2  9.951429  92.78354             NA          NA        NA
       # 3     1     3 12.831509  95.00553             NA          NA        NA
       # 4     1     4 12.463664  95.37171      11.277950 -0.10312483 11.381075
       # 5     1     5 11.781704  92.05240      11.757076 -0.06945881 11.826535
       # 6     1     6 12.756932  92.15666      12.458452 -0.27064269 12.729095
       # 7     1     7 12.346409  94.32411      12.337177 -0.09952197 12.436699
       # 8     1     8 10.223695 100.89043      11.777185  0.83961377 10.937571
       # 9     1     9  4.031945  87.38217       9.839745 -0.45357658 10.293322
      # 10     1    10 11.859477  97.96973       9.615382  0.34633428  9.269047
      # ... with 50 more rows
      

      编辑你可以用%&gt;% nest(-id)仍然嵌套结果

      如果您仍然喜欢嵌套或出于其他原因正在嵌套,它会像

      t1 <- t_nest %>% 
              mutate(data = map(data, ~.x %>% mutate(...)))
      

      也就是说,您在 map 语句中对 .x 进行变异。这会将data 视为data.framemutate 会将结果列绑定到它。

      【讨论】:

      • 感谢@Cpak。是的,在嵌套数据之外做可能更简单,但在我的真实数据集中更复杂,我想存储嵌套的纵向数据以保持紧凑。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多