У меня есть список списков фреймов данных, где каждый фрейм данных имеет имя в соответствии с его позицией в списке. Я хочу rbind
объединить мои фреймы данных в соответствии с их именем.
A1 <- data.frame(cars*rnorm(50,2))
B1 <- data.frame(cars*rnorm(60,2))
C1 <- data.frame(cars*rnorm(70,2))
A2 <- data.frame(cars*rnorm(50,2))
B2 <- data.frame(cars*rnorm(60,2))
C2 <- data.frame(cars*rnorm(70,2))
A3 <- data.frame(cars*rnorm(50,2))
B3 <- data.frame(cars*rnorm(60,2))
C3 <- data.frame(cars*rnorm(70,2))
Gen1 <- list(A1,B1,C1) ; names(Gen1) <- c('A','B','C')
Gen2 <- list(A2,B2,C2) ; names(Gen2) <- c('A','B','C')
Gen3 <- list(A3,B3,C3) ; names(Gen3) <- c('A','B','C')
Data1 <- list(Gen1, Gen2, Gen3) ; names(Data1) <- c('Gen1', 'Gen2', 'Gen3')
# Example of desired output
A_values <- rbind(Gen1$A, Gen2$A, Gen3$A)
B_values <- rbind(Gen1$B, Gen2$B, Gen3$B)
C_values <- rbind(Gen1$C, Gen2$C, Gen3$C)
output <- list(A_values, B_values, C_values)
output
иллюстрирует то, что я пытаюсь получить, но я хочу использовать функцию Apply Family для Data1
, где мне не нужно указывать каждый элемент в каждом списке по имени.
В этом посте рассматривается аналогичная проблема, но решение с использованием lapply
приводит к списку, сгруппированному по «верхнему» уровню списка (Gen
), а не по «нижнему» уровню списка (A
, B
или C
).
TEST <- lapply(split(Data1, names(Data1)), function(i){
xsub <- do.call(c, unname(i))
lapply(split(xsub, names(xsub)), function(j) do.call(rbind, unname(j)))
})
str(TEST)
List of 3
$ Gen1:List of 3
..$ A:'data.frame': 50 obs. of 2 variables:
.. ..$ A.speed: num [1:50] 10.54 8.98 6.12 16.78 7.25 ...
.. ..$ A.dist : num [1:50] 5.27 22.44 3.5 52.74 14.5 ...
..$ B:'data.frame': 50 obs. of 2 variables:
.. ..$ B.speed: num [1:50] 3.699 3.199 13.915 -0.945 9.957 ...
.. ..$ B.dist : num [1:50] 5.54 36.25 17.13 -5.3 37.93 ...
..$ C:'data.frame': 50 obs. of 2 variables:
.. ..$ C.speed: num [1:50] 14.72 12.95 8.58 16.55 13.02 ...
.. ..$ C.dist : num [1:50] 2.11 11.98 3.82 32.4 8.97 ...
$ Gen2:List of 3
$ Gen3:List of 3
Я тоже пробовал tapply
, но безуспешно. Любая помощь очень ценится. Спасибо!
library(tidyverse)
my_output <- Data1 |>
list_transpose() |>
map(bind_rows)
str(my_output)
List of 3 $ A:'data.frame': 150 obs. of 2 variables: ..$ speed: num [1:150] 4.35 2.92 5.11 21.88 11.12 ... ..$ dist : num [1:150] 2.18 7.29 2.92 68.76 22.23 ... $ B:'data.frame': 150 obs. of 2 variables: ..$ speed: num [1:150] 10.3 8.75 9.99 15.3 18.86 ... ..$ dist : num [1:150] 5.14 40.54 8.35 43.6 31.41 ... $ C:'data.frame': 150 obs. of 2 variables: ..$ speed: num [1:150] 2.74 4.56 13.52 7.26 24.34 ... ..$ dist : num [1:150] 5.15 6.68 1.98 29.18 50.56 ...
Обратите внимание, что list_transpose
транспонируется на основе имен, если они есть, и это то, что вам нужно.
В базе все немного запутаннее:
names(Data1[[1]]) |>
lapply(\(i) lapply(Data1, `[[`, i)) |>
lapply(\(x) do.call(rbind, x))
@thelatemail Очень здорово, думаю, я мог бы часами рассматривать эту проблему и не придумать ее.
В конечном итоге я добился этого, используя подход на базе R: do.call(Map, c(rbind, Data1))
Подход tidyverse
с использованием list_transpose
также работает.
Я думаю, базовая версия не должна быть такой сложной -
do.call(Map, c(rbind, Data1))