Как добавить столбец в списки в списке, не теряя их имен? - PullRequest
0 голосов
/ 10 декабря 2018

Я сделал несколько попыток добавить определенный столбец во фреймы данных, соответственно.списки в списке, но все попытки *apply() не смогли сохранить имена фреймов данных.

Например, для списка l,

l <- list(alpha=data.frame(1:3), bravo=data.frame(4:6), charly=data.frame(7:9))

> l
$`alpha`
  X1.3
1    1
2    2
3    3

$bravo
  X4.6
1    4
2    5
3    6

$charly
  X7.9
1    7
2    8
3    9

Мне нужны начальные буквыимена списков в виде второго id столбца.Я попробовал эти попытки, которые дают мне в основном то, что я хочу:

lapply(seq_along(l), function(x) cbind(l[[x]], id=substr(names(l)[x], 1, 1)))
# or
lapply(seq_along(l), function(x) data.frame(l[[x]], id=substr(names(l)[x], 1, 1)))
# [[1]]
# X1.3 id
# 1    1  a
# 2    2  a
# 3    3  a
# 
# [[2]]
# X4.6 id
# 1    4  b
# 2    5  b
# 3    6  b
# 
# [[3]]
# X7.9 id
# 1    7  c
# 2    8  c
# 3    9  c

, но внутренние списки потеряли свои имена.Опция USE.NAMES=TRUE из lapply() документации не сработала.

Я также попробовал эти две попытки, но они провалились еще хуже.

lapply(seq_along(l), function(x) mapply(cbind, l[[x]], id=substr(names(l)[x], 1, 1), 
                                        SIMPLIFY=FALSE))
rapply(l, function(x) cbind(x, id=substr(names(l)[x], 1, 1)), how="list")

Я знаю, что мог бы сделать это так:

l1 <- lapply(seq_along(l), function(x) cbind(l[[x]], id=substr(names(l)[x], 1, 1)))
names(l1) <- names(l)

или выполните цикл for:

for(i in seq_along(l)) {
  l[[i]] <- data.frame(l[[i]], id=substr(names(l)[i], 1, 1))
}

, но я хотел бы знать, можно ли улучшить решение *apply() для получения ожидаемого результата, чтобудет:

$`alpha`
  X1.3 id
1    1  a
2    2  a
3    3  a

$bravo
  X4.6 id
1    4  b
2    5  b
3    6  b

$charly
  X7.9 id
1    7  c
2    8  c
3    9  c

Ответы [ 3 ]

0 голосов
/ 10 декабря 2018

sapply над именами с simplify = FALSE.

addId <- function(x) cbind(l[[x]], id = substring(x, 1, 1))
sapply(names(l), addId, simplify = FALSE)

, дающими:

$`alpha`
  X1.3 id
1    1  a
2    2  a
3    3  a

$bravo
  X4.6 id
1    4  b
2    5  b
3    6  b

$charly
  X7.9 id
1    7  c
2    8  c
3    9  c

Поочередно:

replace(l, TRUE, lapply(names(l), addId))
0 голосов
/ 10 декабря 2018

Если вы не возражаете переключиться на семейство purrr::map из семейства apply, purrr::imap принимает 2 аргумента: сопоставляемый элемент и имена сопоставляемого элемента.Тогда вы можете использовать тот же самый вызов cbind, но теперь у вас есть легкий доступ к именам фреймов данных.

l <- list(alpha=data.frame(1:3), bravo=data.frame(4:6), charly=data.frame(7:9))

purrr::imap(l, function(df, name) cbind(df, id = substr(name, 1, 1)))
#> $alpha
#>   X1.3 id
#> 1    1  a
#> 2    2  a
#> 3    3  a
#> 
#> $bravo
#>   X4.6 id
#> 1    4  b
#> 2    5  b
#> 3    6  b
#> 
#> $charly
#>   X7.9 id
#> 1    7  c
#> 2    8  c
#> 3    9  c

Или, если вы хотите заполнить tidyverse, вы можете добавить столбецс dplyr::mutate внутри вашего imap.

library(tidyverse)

imap(l, function(df, name) df %>% mutate(id = str_sub(name, 1, 1)))
#> $alpha
#>   X1.3 id
#> 1    1  a
#> 2    2  a
#> 3    3  a
#> 
#> $bravo
#>   X4.6 id
#> 1    4  b
#> 2    5  b
#> 3    6  b
#> 
#> $charly
#>   X7.9 id
#> 1    7  c
#> 2    8  c
#> 3    9  c

Как отмечает @markus, вы также можете использовать сокращенную запись формулы ~. вместо того, чтобы излагать свои функции.В этом случае два аргумента purrr::imap становятся .x (фреймы данных) и .y (имена).Это выглядит так:

purrr::imap(l, ~cbind(.x, id = substr(.y, 1, 1)))
0 голосов
/ 10 декабря 2018

Попробуйте Map

Map(`[<-`, l, "id", value = substr(names(l), 1, 1))
#$alpha
#  X1.3 id
#1    1  a
#2    2  a
#3    3  a

#$bravo
#  X4.6 id
#1    4  b
#2    5  b
#3    6  b

#$charly
#  X7.9 id
#1    7  c
#2    8  c
#3    9  c

Первый аргумент - это функция.Map затем применяет функцию "к первым элементам каждого ... аргумента, вторым элементам, третьим элементам и т. Д.", См. ?mapply.

...