根据 R 中的名称应用多个函数来列出元素
Apply multiple functions to list elements based on their name in R
考虑以下列表结构:
AA <- data.frame("variable1" = c("a", "b"), "variable2" = 1:2)
BB <- data.frame("variable1" = c("a", "b"), "variable2" = 3:4)
my_list <- list(AA=AA, BB=BB)
> my_list
$AA
variable1 variable2
1 a 1
2 b 2
$BB
variable1 variable2
1 a 3
2 b 4
即使 my_list
中的各个列表元素具有相同的 variable1
名称 a
和 b
,这些元素对于每个列表元素也必须被视为唯一的(因为真实数据具有类似的重复变量名称和值)。因此,我有两个函数旨在操纵每个特定的列表元素:
AA_recoding <- function(x) {
x$variable1 <- x$variable1 %>%
recode("a" = "hello")
return(x)
}
BB_recoding <- function(x) {
x$variable1 <- x$variable1 %>%
recode("a" = "goodbye")
return(x)
}
我的objective是对AA
列表元素应用AA_recoding
函数,对BB
应用BB_recoding
函数,实现一个像这样输出:
$AA
variable1 variable2
1 hello 1
2 b 2
$BB
variable1 variable2
1 goodbye 3
2 b 4
这似乎是 purrr
函数(如 map
/imap
)的工作,但我看不到一种方法可以将我的函数专门定向到它们各自的列表元素按名字。我尝试使用 glue
(和 paste0
)遇到以下错误:
> my_list %>% imap(~.x %>% glue("{.y}_recoding"))
Error: All unnamed arguments must be length 1
> my_list %>% map(~.x %>% paste0(.y,"_recoding"))
Error in paste0(., .y, "_recoding") :
the ... list contains fewer than 2 elements
我是否从根本上以正确的方式解决了这个问题?
我们可以使用 map2
,通过将函数包装在 list
中,将相应的函数应用于 list
的元素
library(purrr)
map2(my_list, list(AA_recoding, BB_recoding), ~ .y(.x))
#$AA
# variable1 variable2
#1 hello 1
#2 b 2
#$BB
# variable1 variable2
#1 goodbye 3
#2 b 4
请注意,上面的 list
(list(AA_recoding, BB_recoding)
) 是按照与 'my_list' 中相同的名称顺序手动创建的,但它也可以使用 [=19= 自动创建]和mget
(到return的值)
library(stringr)
map2(my_list, mget(str_c(names(my_list), '_recoding')), ~ .y(.x))
或者如果我们想从 imap
的 list
的 names
中获取函数值,要么通过用 match.fun
[=26 换行来获取值=]
my_list %>%
imap(~ match.fun(str_c(.y, '_recoding'))(.x))
或使用get
my_list %>%
imap(~ get(str_c(.y, '_recoding'))(.x))
根据您有多少条件,您可以将您的函数组合成一个单独的重新编码函数,然后使用 lapply
根据列表中的项目名称有条件地应用它。
这有点老套,因为 lapply 不保留单个列表的名称。因此,在每个数据框中创建一个与列表名称相对应的列,然后使用 lapply
.
应用新的组合函数
new_list <- my_list
list_names <- c("AA", "BB")
for(i in 1:length(my_list)){
new_list[[i]]$name <- list_names[[i]]
}
> new_list # Looks like this
$AA
variable1 variable2 name
1 a 1 AA
2 b 2 AA
$BB
variable1 variable2 name
1 a 3 BB
2 b 4 BB
# Combined function
AA_BB_recoding <- function(x){
x$variable1 <- ifelse(x$name == "AA", x$variable1 %>%
recode("a" = "hello"), x$variable1 %>%
recode("a" = "goodbye"))
return(x)
}
> lapply(new_list, function(f) AA_BB_recoding(f))
# returns
$AA
variable1 variable2 name
1 hello 1 AA
2 b 2 AA
$BB
variable1 variable2 name
1 goodbye 3 BB
2 b 4 BB
考虑以下列表结构:
AA <- data.frame("variable1" = c("a", "b"), "variable2" = 1:2)
BB <- data.frame("variable1" = c("a", "b"), "variable2" = 3:4)
my_list <- list(AA=AA, BB=BB)
> my_list
$AA
variable1 variable2
1 a 1
2 b 2
$BB
variable1 variable2
1 a 3
2 b 4
即使 my_list
中的各个列表元素具有相同的 variable1
名称 a
和 b
,这些元素对于每个列表元素也必须被视为唯一的(因为真实数据具有类似的重复变量名称和值)。因此,我有两个函数旨在操纵每个特定的列表元素:
AA_recoding <- function(x) {
x$variable1 <- x$variable1 %>%
recode("a" = "hello")
return(x)
}
BB_recoding <- function(x) {
x$variable1 <- x$variable1 %>%
recode("a" = "goodbye")
return(x)
}
我的objective是对AA
列表元素应用AA_recoding
函数,对BB
应用BB_recoding
函数,实现一个像这样输出:
$AA
variable1 variable2
1 hello 1
2 b 2
$BB
variable1 variable2
1 goodbye 3
2 b 4
这似乎是 purrr
函数(如 map
/imap
)的工作,但我看不到一种方法可以将我的函数专门定向到它们各自的列表元素按名字。我尝试使用 glue
(和 paste0
)遇到以下错误:
> my_list %>% imap(~.x %>% glue("{.y}_recoding"))
Error: All unnamed arguments must be length 1
> my_list %>% map(~.x %>% paste0(.y,"_recoding"))
Error in paste0(., .y, "_recoding") :
the ... list contains fewer than 2 elements
我是否从根本上以正确的方式解决了这个问题?
我们可以使用 map2
,通过将函数包装在 list
list
的元素
library(purrr)
map2(my_list, list(AA_recoding, BB_recoding), ~ .y(.x))
#$AA
# variable1 variable2
#1 hello 1
#2 b 2
#$BB
# variable1 variable2
#1 goodbye 3
#2 b 4
请注意,上面的 list
(list(AA_recoding, BB_recoding)
) 是按照与 'my_list' 中相同的名称顺序手动创建的,但它也可以使用 [=19= 自动创建]和mget
(到return的值)
library(stringr)
map2(my_list, mget(str_c(names(my_list), '_recoding')), ~ .y(.x))
或者如果我们想从 imap
的 list
的 names
中获取函数值,要么通过用 match.fun
[=26 换行来获取值=]
my_list %>%
imap(~ match.fun(str_c(.y, '_recoding'))(.x))
或使用get
my_list %>%
imap(~ get(str_c(.y, '_recoding'))(.x))
根据您有多少条件,您可以将您的函数组合成一个单独的重新编码函数,然后使用 lapply
根据列表中的项目名称有条件地应用它。
这有点老套,因为 lapply 不保留单个列表的名称。因此,在每个数据框中创建一个与列表名称相对应的列,然后使用 lapply
.
new_list <- my_list
list_names <- c("AA", "BB")
for(i in 1:length(my_list)){
new_list[[i]]$name <- list_names[[i]]
}
> new_list # Looks like this
$AA
variable1 variable2 name
1 a 1 AA
2 b 2 AA
$BB
variable1 variable2 name
1 a 3 BB
2 b 4 BB
# Combined function
AA_BB_recoding <- function(x){
x$variable1 <- ifelse(x$name == "AA", x$variable1 %>%
recode("a" = "hello"), x$variable1 %>%
recode("a" = "goodbye"))
return(x)
}
> lapply(new_list, function(f) AA_BB_recoding(f))
# returns
$AA
variable1 variable2 name
1 hello 1 AA
2 b 2 AA
$BB
variable1 variable2 name
1 goodbye 3 BB
2 b 4 BB