簡體   English   中英

將data.frames列表的列表轉換為R中的單個data.frame

[英]Converting a list of list of data.frames to a single data.frame in R

我有一個data.frames list list (見下面的L )。

我想知道是否可以將L轉換為我所需的輸出,如下所示 ,這是一個data.frame

L <- list(A = list(Short = data.frame(d = 1:2, SD = 3:4)), 
          B = list(Short = data.frame(d = 2:3, SD = 1:2), Long1 = data.frame(d = 7:8, SD = 6:7)),
          C = list(Short = data.frame(d = 5:6, SD = 3:4), Long1 = data.frame(d = 8:9, SD = 1:2), 
               Long2 = data.frame(d = 4:5, SD = 6:7)))

期望的輸出( data.frame ):

d  SD id
1  3   1
2  4   1
2  1   2
3  2   2
7  6   2
8  7   2
5  3   3
6  4   3
8  1   3
9  2   3
4  6   3
5  7   3

我們可以嘗試對L每個列表進行rbinding並添加一個新列,該列表示列表編號,最后使用do.callrbind將整個列表放入一個數據幀中。

output <- do.call(rbind, lapply(seq_along(L), function(x) 
                          transform(do.call(rbind, L[[x]]), id = x)))
rownames(output) <- NULL

output
#   d SD id
#1  1  3  1
#2  2  4  1
#3  2  1  2
#4  3  2  2
#5  7  6  2
#6  8  7  2
#7  5  3  3
#8  6  4  3
#9  8  1  3
#10 9  2  3
#11 4  6  3
#12 5  7  3

使用dplyrbind_rowspurrr::map可能會稍微短bind_rows ,但是這purrr::map id變量作為列表的名稱( ABC )而不是序列,這不應該很難改變。

library(dplyr)
bind_rows(purrr::map(L, bind_rows), .id = "id")  %>%
          mutate(id = match(id, unique(id)))

我們可以在base R使用lapply/Map 我們可以使用lapply循環遍歷listrbind嵌套list元素,然后使用Map創建一個新列並對外部list元素進行rbind

out <- do.call(rbind, Map(cbind, lapply(L, function(x) 
              do.call(rbind, x)), id = seq_along(L)))
row.names(out) <- NULL
out
#   d SD id
#1  1  3  1
#2  2  4  1
#3  2  1  2
#4  3  2  2
#5  7  6  2
#6  8  7  2
#7  5  3  3
#8  6  4  3
#9  8  1  3
#10 9  2  3
#11 4  6  3
#12 5  7  3

根據注釋,如果我們需要從內部listnames添加另一列

out1 <- do.call(rbind, Map(cbind, lapply(L, function(dat)
   do.call(rbind, Map(cbind, dat, es.type = names(dat)))), id = seq_along(L)))
row.names(out1) <- NULL

out1
#   d SD es.type id
#1  1  3   Short  1
#2  2  4   Short  1
#3  2  1   Short  2
#4  3  2   Short  2
#5  7  6   Long1  2
#6  8  7   Long1  2
#7  5  3   Short  3
#8  6  4   Short  3
#9  8  1   Long1  3
#10 9  2   Long1  3
#11 4  6   Long2  3
#12 5  7   Long2  3

如果有..\\\\d+並想要刪除

out1 <- do.call(rbind, Map(cbind, lapply(L, function(dat)
   do.call(rbind, Map(cbind, dat, 
     es.type = sub("\\.*\\d+$", "", names(dat))))), id = seq_along(L)))
row.names(out1) <- NULL
out1
#   d SD es.type id
#1  1  3   Short  1
#2  2  4   Short  1
#3  2  1   Short  2
#4  3  2   Short  2
#5  7  6    Long  2
#6  8  7    Long  2
#7  5  3   Short  3
#8  6  4   Short  3
#9  8  1    Long  3
#10 9  2    Long  3
#11 4  6    Long  3
#12 5  7    Long  3

這是使用purrr的flatten_dfr另一種可能的方法:

library(purrr)

transform(flatten_dfr(L), id = rep(seq_along(L), times = map(L, ~sum(lengths(.x)))))
#>    d SD id
#> 1  1  3  1
#> 2  2  4  1
#> 3  2  1  2
#> 4  3  2  2
#> 5  7  6  2
#> 6  8  7  2
#> 7  5  3  3
#> 8  6  4  3
#> 9  8  1  3
#> 10 9  2  3
#> 11 4  6  3
#> 12 5  7  3

注意:這里我使用了基本R的transform ,可以用dplyr的mutate代替

rbindlist()是一個便利函數,它從許多列表中生成一個data.table。 對於這個嵌套列表,它必須遞歸地應用兩次。

此外,它具有idcol參數,該參數在結果中創建一個列,顯示這些行來自哪個列表項。

library(data.table)
rbindlist(lapply(L, rbindlist, idcol = "es.type"), idcol = "id")
  id es.type d SD 1: A Short 1 3 2: A Short 2 4 3: B Short 2 1 4: B Short 3 2 5: B Long1 7 6 6: B Long1 8 7 7: C Short 5 3 8: C Short 6 4 9: C Long1 8 1 10: C Long1 9 2 11: C Long2 4 6 12: C Long2 5 7 

現在,OP已要求id是數字和Long1Long2必須成為Long 這可以通過對結果列的后續操作來實現:

rbindlist(lapply(L, rbindlist, idcol = "es.type"), idcol = "id")[
  , id := rleid(id)][
    , es.type := sub("\\d+$", "", es.type)][]
  id es.type d SD 1: 1 Short 1 3 2: 1 Short 2 4 3: 2 Short 2 1 4: 2 Short 3 2 5: 2 Long 7 6 6: 2 Long 8 7 7: 3 Short 5 3 8: 3 Short 6 4 9: 3 Long 8 1 10: 3 Long 9 2 11: 3 Long 4 6 12: 3 Long 5 7 

在基數R中,我們可以實現相同的目標

do.call("rbind", lapply(L, do.call, what = "rbind"))

返回

  d SD A.Short.1 1 3 A.Short.2 2 4 B.Short.1 2 1 B.Short.2 3 2 B.Long1.1 7 6 B.Long1.2 8 7 C.Short.1 5 3 C.Short.2 6 4 C.Long1.1 8 1 C.Long1.2 9 2 C.Long2.1 4 6 C.Long2.2 5 7 

可以從解析行名稱中檢索ides.type ,例如,

DF <- do.call("rbind", lapply(L, do.call, what = "rbind"))
id <- stringr::str_extract(row.names(DF), "^[^.]*")
# create sequence number (that's what data.table::rleid() does)
DF$id <- c(1L, cumsum(head(id, -1L) != tail(id, -1L)) + 1L)
DF$es.type <- stringr::str_extract(row.names(DF), "(?<=\\.)[^.0-9]*")
row.names(DF) <- NULL
DF
  d SD id es.type 1 1 3 1 Short 2 2 4 1 Short 3 2 1 2 Short 4 3 2 2 Short 5 7 6 2 Long 6 8 7 2 Long 7 5 3 3 Short 8 6 4 3 Short 9 8 1 3 Long 10 9 2 3 Long 11 4 6 3 Long 12 5 7 3 Long 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM