purrr 遍历一个数据帧的列并有条件地替换另一个数据帧的值
purrr loop through columns of one dataframe and conditionally replace values from another dataframe
有了以下数据...
library(tidyverse)
df_fac <- data_frame("author_1" = c("Ted", "Fred", NA, "Jim", "Tim"),
"role_1" = c("Faculty", "Faculty", "Staff", "Faculty", "Faculty"),
"author_2" = c(NA, "Will", NA, "Bill", NA),
"role_2" = c("Staff", "Faculty", "Staff", "Faculty", "Staff"))
df_all <- data_frame("author_1" = c("Ted", "Fred", "Simon", "Jim", "Tim"),
"role_1" = c("Faculty", "Faculty", "Staff", "Faculty", "Faculty"),
"author_2" = c("Sam", "Will", "Noah", "Bill", "Luther"),
"role_2" = c("Staff", "Faculty", "Staff", "Faculty", "Staff"))
如果 df_fac
中的 "author" 列是 NA
,我希望它们使用 [=18] 从 df_all
中相应的列值中填充=] 功能来自 purrr
。这是我目前在没有循环的情况下所做的:
df_test <- df_fac %>%
mutate(`author_1` = ifelse(is.na(`author_1`), df_all$`author_1`, `author_1`)) %>%
mutate(`author_2` = ifelse(is.na(`author_2`), df_all$`author_2`, `author_2`))
使用 map_df
我可以迭代 df_fac
中的列,但不能在 df_all
中迭代(如您所见,它只是作者第 1 列)。
df_test <- map_df(select(df_fac, matches("author.\d$")), ~ {
ifelse(is.na(.), df_all$`author_1`, .)
})
有没有办法让 map_df
在迭代 select(df_fac, matches("author.\d$"))
的同时迭代 select(df_all, matches("author.\d$"))
?
对于玩具示例,df_test
应该与 df_all
具有相同的作者列和值。我试过:
df_test <- map_df(1:length(select(df_fac, matches("author.\d$"))), ~ {
ifelse(is.na(select(df_fac, matches("author.\d$"))[.]),
select(df_all, matches("author.\d$"))[.],
select(df_fac, matches("author.\d$"))[.])
})
抛出 Error in bind_rows_(x, .id) : not compatible with STRSXP
df_test <- pmap_chr(list(is.na(select(df_fac, matches("author.\d$"))),
select(df_all, matches("author.\d$")),
select(df_fac, matches("author.\d$"))),
ifelse)
抛出 Error: Element 2 has length 2, not 1 or 10.
我需要使用 matches
函数,因为实际数据中有很多作者列与类似的变量名称混合在一起。如果不清楚,我可以澄清一下。谢谢。
您可以使用 map2_df
同时循环遍历两个列表。使用 dplyr::coalsece
将有助于替换缺失值。我使用 select
来确保 df_all
中的列与 df_fac
.
中的列相同且顺序相同
map2_df(df_fac, select(df_all, one_of(names(df_fac))), ~coalesce(.x, .y))
同样的事情使用 pmap
:
pmap_df(list(df_fac, select(df_all, one_of(names(df_fac)))), coalesce)
您也可以将 ifelse
与 map2
结合使用,连同公式符号来指代您正在使用的两个不同列表。
map2_df(df_fac, select(df_all, one_of(names(df_fac))),
~ifelse(is.na(.x), .y, .x))
有了以下数据...
library(tidyverse)
df_fac <- data_frame("author_1" = c("Ted", "Fred", NA, "Jim", "Tim"),
"role_1" = c("Faculty", "Faculty", "Staff", "Faculty", "Faculty"),
"author_2" = c(NA, "Will", NA, "Bill", NA),
"role_2" = c("Staff", "Faculty", "Staff", "Faculty", "Staff"))
df_all <- data_frame("author_1" = c("Ted", "Fred", "Simon", "Jim", "Tim"),
"role_1" = c("Faculty", "Faculty", "Staff", "Faculty", "Faculty"),
"author_2" = c("Sam", "Will", "Noah", "Bill", "Luther"),
"role_2" = c("Staff", "Faculty", "Staff", "Faculty", "Staff"))
如果 df_fac
中的 "author" 列是 NA
,我希望它们使用 [=18] 从 df_all
中相应的列值中填充=] 功能来自 purrr
。这是我目前在没有循环的情况下所做的:
df_test <- df_fac %>%
mutate(`author_1` = ifelse(is.na(`author_1`), df_all$`author_1`, `author_1`)) %>%
mutate(`author_2` = ifelse(is.na(`author_2`), df_all$`author_2`, `author_2`))
使用 map_df
我可以迭代 df_fac
中的列,但不能在 df_all
中迭代(如您所见,它只是作者第 1 列)。
df_test <- map_df(select(df_fac, matches("author.\d$")), ~ {
ifelse(is.na(.), df_all$`author_1`, .)
})
有没有办法让 map_df
在迭代 select(df_fac, matches("author.\d$"))
的同时迭代 select(df_all, matches("author.\d$"))
?
对于玩具示例,df_test
应该与 df_all
具有相同的作者列和值。我试过:
df_test <- map_df(1:length(select(df_fac, matches("author.\d$"))), ~ {
ifelse(is.na(select(df_fac, matches("author.\d$"))[.]),
select(df_all, matches("author.\d$"))[.],
select(df_fac, matches("author.\d$"))[.])
})
抛出 Error in bind_rows_(x, .id) : not compatible with STRSXP
df_test <- pmap_chr(list(is.na(select(df_fac, matches("author.\d$"))),
select(df_all, matches("author.\d$")),
select(df_fac, matches("author.\d$"))),
ifelse)
抛出 Error: Element 2 has length 2, not 1 or 10.
我需要使用 matches
函数,因为实际数据中有很多作者列与类似的变量名称混合在一起。如果不清楚,我可以澄清一下。谢谢。
您可以使用 map2_df
同时循环遍历两个列表。使用 dplyr::coalsece
将有助于替换缺失值。我使用 select
来确保 df_all
中的列与 df_fac
.
map2_df(df_fac, select(df_all, one_of(names(df_fac))), ~coalesce(.x, .y))
同样的事情使用 pmap
:
pmap_df(list(df_fac, select(df_all, one_of(names(df_fac)))), coalesce)
您也可以将 ifelse
与 map2
结合使用,连同公式符号来指代您正在使用的两个不同列表。
map2_df(df_fac, select(df_all, one_of(names(df_fac))),
~ifelse(is.na(.x), .y, .x))