从嵌套列表中提取数据,然后转换为整洁的数据框

时间:2019-07-24 19:19:37

标签: r tidyverse purrr

我有一个数据重新格式化问题,需要帮助!我从一个列表列表开始,我想将其变成一个“整洁”的数据框,以便我进一步分析。

我的列表列表的结构如下:

str(wells, list.len = 3)  
    List of 96  
     $ A1 :List of 2  
      ..$ times : num [1:96] 0 900 1800 2700 3600 4500 5400 6300 7200 8100 ...  
      ..$ values: num [1:80] 0.0966 0.0928 0.0924 0.0931 0.0931 0.0939 0.0937 0.0938 0.0943 0.0949 ...  
      ..- attr(*, "name")= chr "A1"  
      ..- attr(*, "class")= chr "softermax.well"  
      ..- attr(*, "ID")= chr "1"  
      ..- attr(*, "row")= int 1  
      ..- attr(*, "col")= int 1  
     $ A2 :List of 2  
      ..$ times : num [1:96] 0 900 1800 2700 3600 4500 5400 6300 7200 8100 ...  
      ..$ values: num [1:80] 0.0945 0.0915 0.0912 0.0911 0.0913 0.0918 0.0921 0.0921 0.0923 0.0934 ...  
      ..- attr(*, "name")= chr "A2"  
      ..- attr(*, "class")= chr "softermax.well"  
      ..- attr(*, "ID")= chr "2"  
      ..- attr(*, "row")= int 1  
      ..- attr(*, "col")= int 2  
     $ A3 :List of 2  
      ..$ times : num [1:96] 0 900 1800 2700 3600 4500 5400 6300 7200 8100 ...  
      ..$ values: num [1:80] 0.0932 0.09 0.0898 0.0896 0.0898 0.0901 0.0903 0.0903 0.0911 0.0918 ...  
      ..- attr(*, "name")= chr "A3"  
      ..- attr(*, "class")= chr "softermax.well"  
      ..- attr(*, "ID")= chr "3"  
      ..- attr(*, "row")= int 1  
      ..- attr(*, "col")= int 3  

我希望生成的数据框具有三列,即“名称”,“时间”和“值”。 “名称”应该是每个顶级列表条目的“名称”属性-每个“名称”的值在最终数据框中应该有80行,其中“时间”和“值”是前80个条目从“时间”和“值”子列表中。 “时间”的第81至第96个条目是NA,需要将其删除,以便“时间”和“值”列表的长度相同。

我一直在玩tidyverse的purr和地图。我可以提取一些想要的片段,但是还无法弄清楚如何将它们放在一起。

我可以通过以下方式获得“名称”列表: wellnames <- attributes(wells)

我可以使用purrr :: map为每个子列表提取“时间”和“值”,如下所示: x <- map(wells, [, c("times", "values")) 但由于“时间”和“值”具有不同的长度(分别为96和80,因为“时间”末尾有额外的NA值),因此无法将列表的结果列表转换为数据框。

我可以为第一个子列表提取所需的“时间”值: wells$A1$times[!is.na(wells$A1$times)] 但无法弄清楚如何使用purrr和带有is.na的map函数为96个子列表中的每一个提取所需的“时间”值。

如果我可以得到没有NA值的“时间”,那么将片段转换成一个或多个数据帧并根据需要使用dplyr进行整形/合并应该相当简单。

我知道这个问题必须有一个整洁的解决方案。我只是还不能弄清楚处理嵌套和NA的语法。

以下是前三个子列表的完整数据集:

dput(wells[1:3])  
structure(list(A1 = structure(list(times = c(0, 900, 1800, 2700, 
3600, 4500, 5400, 6300, 7200, 8100, 9000, 9900, 10800, 11700, 
12600, 13500, 14400, 15300, 16200, 17100, 18000, 18900, 19800, 
20700, 21600, 22500, 23400, 24300, 25200, 26100, 27000, 27900, 
28800, 29700, 30600, 31500, 32400, 33300, 34200, 35100, 36000, 
36900, 37800, 38700, 39600, 40500, 41400, 42300, 43200, 44100, 
45000, 45900, 46800, 47700, 48600, 49500, 50400, 51300, 52200, 
53100, 54000, 54900, 55800, 56700, 57600, 58500, 59400, 60300, 
61200, 62100, 63000, 63900, 64800, 65700, 66600, 67500, 68400, 
69300, 70200, 71100, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA, NA, NA, NA, NA), values = c(0.0966, 0.0928, 0.0924, 0.0931, 
0.0931, 0.0939, 0.0937, 0.0938, 0.0943, 0.0949, 0.0951, 0.096, 
0.0968, 0.098, 0.0991, 0.1004, 0.102, 0.1034, 0.1054, 0.1078, 
0.1103, 0.1132, 0.1161, 0.1196, 0.1234, 0.1279, 0.1329, 0.1381, 
0.144, 0.1505, 0.1574, 0.1648, 0.1732, 0.1819, 0.1912, 0.2018, 
0.2127, 0.232, 0.2436, 0.329, 0.4145, 0.3683, 0.4234, 0.5003, 
0.5291, 0.5463, 0.5472, 0.5664, 0.5649, 0.5618, 0.5487, 0.5494, 
0.5372, 0.5241, 0.4825, 0.5502, 0.544, 0.5415, 0.5319, 0.5234, 
0.5174, 0.5146, 0.5098, 0.4848, 0.3679, 0.3651, 0.3627, 0.3574, 
0.3686, 0.3577, 0.3689, 0.3528, 0.3584, 0.3573, 0.3471, 0.3571, 
0.3556, 0.3536, 0.3648, 0.3428)), .Names = c("times", "values"
), name = "A1", class = "softermax.well", ID = "1", row = 1L, col = 1L), 
    A2 = structure(list(times = c(0, 900, 1800, 2700, 3600, 4500, 
    5400, 6300, 7200, 8100, 9000, 9900, 10800, 11700, 12600, 
    13500, 14400, 15300, 16200, 17100, 18000, 18900, 19800, 20700, 
    21600, 22500, 23400, 24300, 25200, 26100, 27000, 27900, 28800, 
    29700, 30600, 31500, 32400, 33300, 34200, 35100, 36000, 36900, 
    37800, 38700, 39600, 40500, 41400, 42300, 43200, 44100, 45000, 
    45900, 46800, 47700, 48600, 49500, 50400, 51300, 52200, 53100, 
    54000, 54900, 55800, 56700, 57600, 58500, 59400, 60300, 61200, 
    62100, 63000, 63900, 64800, 65700, 66600, 67500, 68400, 69300, 
    70200, 71100, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, NA, NA, NA, NA), values = c(0.0945, 0.0915, 0.0912, 0.0911, 
    0.0913, 0.0918, 0.0921, 0.0921, 0.0923, 0.0934, 0.094, 0.0949, 
    0.0958, 0.0965, 0.098, 0.0994, 0.101, 0.1028, 0.1054, 0.1079, 
    0.1108, 0.1138, 0.1173, 0.1219, 0.1261, 0.1313, 0.1366, 0.1431, 
    0.1497, 0.1572, 0.1657, 0.1742, 0.1846, 0.195, 0.2066, 0.2203, 
    0.2329, 0.2507, 0.3472, 0.3383, 0.2988, 0.5052, 0.5218, 0.5425, 
    0.4873, 0.45, 0.532, 0.5555, 0.5582, 0.5819, 0.5856, 0.5698, 
    0.5713, 0.5837, 0.5698, 0.5674, 0.5612, 0.562, 0.5605, 0.5498, 
    0.5597, 0.556, 0.5412, 0.5382, 0.5329, 0.5367, 0.5417, 0.525, 
    0.5205, 0.532, 0.5119, 0.5255, 0.5138, 0.523, 0.5128, 0.5227, 
    0.5114, 0.5244, 0.5193, 0.5089)), .Names = c("times", "values"
    ), name = "A2", class = "softermax.well", ID = "2", row = 1L, col = 2L), 
    A3 = structure(list(times = c(0, 900, 1800, 2700, 3600, 4500, 
    5400, 6300, 7200, 8100, 9000, 9900, 10800, 11700, 12600, 
    13500, 14400, 15300, 16200, 17100, 18000, 18900, 19800, 20700, 
    21600, 22500, 23400, 24300, 25200, 26100, 27000, 27900, 28800, 
    29700, 30600, 31500, 32400, 33300, 34200, 35100, 36000, 36900, 
    37800, 38700, 39600, 40500, 41400, 42300, 43200, 44100, 45000, 
    45900, 46800, 47700, 48600, 49500, 50400, 51300, 52200, 53100, 
    54000, 54900, 55800, 56700, 57600, 58500, 59400, 60300, 61200, 
    62100, 63000, 63900, 64800, 65700, 66600, 67500, 68400, 69300, 
    70200, 71100, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, NA, NA, NA, NA), values = c(0.0932, 0.09, 0.0898, 0.0896, 
    0.0898, 0.0901, 0.0903, 0.0903, 0.0911, 0.0918, 0.0925, 0.0935, 
    0.0943, 0.0952, 0.0967, 0.0977, 0.1, 0.1018, 0.1041, 0.1067, 
    0.1092, 0.1156, 0.1151, 0.1193, 0.1238, 0.1284, 0.1334, 0.1402, 
    0.1464, 0.1533, 0.1614, 0.1698, 0.178, 0.1883, 0.1981, 0.2098, 
    0.2216, 0.2437, 0.3692, 0.4148, 0.4345, 0.4958, 0.5029, 0.4899, 
    0.5336, 0.5654, 0.547, 0.486, 0.5027, 0.5277, 0.4908, 0.5641, 
    0.5867, 0.5822, 0.5615, 0.5527, 0.5519, 0.5292, 0.3352, 0.3579, 
    0.3604, 0.3638, 0.366, 0.3787, 0.3737, 0.3645, 0.3674, 0.3794, 
    0.3589, 0.3981, 0.3361, 0.3508, 0.3217, 0.3196, 0.3176, 0.3645, 
    0.3532, 0.3528, 0.3267, 0.3473)), .Names = c("times", "values"
    ), name = "A3", class = "softermax.well", ID = "3", row = 1L, col = 3L)), .Names = c("A1", 
"A2", "A3"))

4 个答案:

答案 0 :(得分:0)

data.table呢?

wells <- data.table::rbindlist(
  lapply(wells, function(x) lapply(x, `[`, 1:80)),
  idcol = 'name'
)

答案 1 :(得分:0)

library(dplyr); library(purrr)

wells %>% 
  map(~tibble(time = na.omit(.x$times), value = na.omit(.x$values))) %>% 
  bind_rows(.id = "name")

对于每个列表元素,使用从父元素的tibbletimes元素中选择的列制作一个values数据框。


更一般而言,如果要将函数应用于嵌套元素,请使用map_depth

wells %>% 
  map_depth(2, na.omit) %>% 
  map(as_tibble) %>% 
  bind_rows(.id = "name")

答案 2 :(得分:0)

您可以使用map_df执行此操作,该操作会自动简化为数据框(小标题)。

wells2 <- map_df(wells,
                 ~tibble(time = .$times[!is.na(.$times)],  #remove NAs to get lengths right
                         value = .$values),
                         .id = "name")                     #adds an id column

答案 3 :(得分:0)

使用tidyverse的另一种可能性:

library(tidyverse)

enframe(na.omit(unlist(wells))) %>% 
  mutate(mrow = str_extract(name, '[[:digit:]]+$'),
         mvar = gsub('A|\\.|[[:digit:]]+', '', name),
         name = str_extract(name, '^A[[:digit:]]+')) %>% 
  spread(key = mvar, value = value) %>% 
  select(-mrow)

#> # A tibble: 240 x 3
#>    name  times values
#>    <chr> <dbl>  <dbl>
#>  1 A1        0 0.0966
#>  2 A1     8100 0.0949
#>  3 A1     9000 0.0951
#>  4 A1     9900 0.096 
#>  5 A1    10800 0.0968
#>  6 A1    11700 0.098 
#>  7 A1    12600 0.0991
#>  8 A1    13500 0.100 
#>  9 A1    14400 0.102 
#> 10 A1    15300 0.103 
#> # ... with 230 more rows