我有一个包含旧值和新值的数据框。如果发生更改,我需要更新新值。我想我真的很亲密,但是我找不到使用tidyverse 的失物。使用base R-使用for循环-可以工作,但是我不想创建新对象或覆盖现有对象。
data <- tribble(~id, ~firstname, ~lastname, ~old_firstname, ~old_lastname,
1, NA, NA, "Peter", "Busch",
2, NA, "Trochen-Pflaume", "Hans", "Trocken")
data%>%
mutate_at(vars(firstname, lastname), ~case_when(
is.na(.) & !is.na(str_c("old_",.)) ~ str_c("old_", .)),
!is.na(.) & . != str_c("old_",.) ~ .)
基本上,唯一要检查的是新值是否为空,然后应采用旧值。结果,计划了查询时更复杂的case_when。但是我无法在mutate_at函数中操纵列名。
我想要什么,但这取决于case_when:
tribble(~id, ~firstname, ~lastname, ~old_firstname, ~old_lastname,
1, "Peter", "Busch", "Peter", "Busch",
2,"Hans", "Trochen-Pflaume", "Hans", "Trocken")
感谢您的帮助!
答案 0 :(得分:1)
这是一个具有挑战性的问题。我正在针对类似问题使用解决方法,但尚未找到使用mutate_at
的方法。 mutate_at
的问题在于我不知道如何访问每个变量的名称。在“普通” mutate/case_when
或transmute/case_when
调用中,您定义!! x :=
,然后可以使用!! sym(x)
访问变量名,并使用!! sym(paste0(“someprefix_”, x))
派生变量名。
使用自定义transmute/case_when
函数可以解决您的问题:
recode_vars <- function(df, x) {
transmute(df,
!! x := case_when(
is.na(!! sym(x)) & !is.na(!! sym(paste0("old_",x))) ~ as.character(!! sym(paste0("old_", x))),
(!is.na(!! sym(x)) & !! sym(x) != !! sym(paste0("old_",x))) ~ as.character(!! sym(x))
)
)
}
# Define here the variable names you want to recode
var_ls <- c("firstname", "lastname")
bind_cols(map_dfc(var_ls, ~ recode_vars(data, .x)),
select(data, -var_ls)) %>%
select(id, everything())
使用map_dfc
,您将获得一个包含所有新重新编码的列的数据框,然后您需要在删除旧列的同时将它们重新绑定到旧数据框,这是可行的,但它并不平滑且确实不会在纯dplyr管道中发生。
我想知道使用mutate_at
代替我上面的方法是否还有更简便的方法。
答案 1 :(得分:0)
如何使用na.locf
包中的zoo
?
library(zoo)
data <- data.frame(t(apply(data[,c(2,4)],1,function(x) na.locf(x,fromLast = T))),
t(apply(data[,c(3,5)],1,function(x) na.locf(x,fromLast = T))))
data <- data[,c(1,3,2,4)]
输出:
> data
firstname lastname old_firstname old_lastname
1 Peter Busch Peter Busch
2 Hans Trochen-Pflaume Hans Trocken