Estas soluciones (1) mantienen la tubería, (2) no sobrescriben la entrada y (3) solo requieren que la condición se especifique una vez:
1a) mutate_cond Crea una función simple para marcos de datos o tablas de datos que se pueden incorporar a las canalizaciones. Esta función es similar mutatepero solo actúa en las filas que cumplen la condición:
mutate_cond <- function(.data, condition, ..., envir = parent.frame()) {
condition <- eval(substitute(condition), .data, envir)
.data[condition, ] <- .data[condition, ] %>% mutate(...)
.data
}
DF %>% mutate_cond(measure == 'exit', qty.exit = qty, cf = 0, delta.watts = 13)
1b) mutate_last Esta es una función alternativa para marcos de datos o tablas de datos que nuevamente es similar mutatepero solo se usa dentro group_by(como en el ejemplo a continuación) y solo opera en el último grupo en lugar de en cada grupo. Tenga en cuenta que TRUE> FALSE, por lo que si group_byespecifica una condición mutate_last, solo funcionará en las filas que satisfagan esa condición.
mutate_last <- function(.data, ...) {
n <- n_groups(.data)
indices <- attr(.data, "indices")[[n]] + 1
.data[indices, ] <- .data[indices, ] %>% mutate(...)
.data
}
DF %>%
group_by(is.exit = measure == 'exit') %>%
mutate_last(qty.exit = qty, cf = 0, delta.watts = 13) %>%
ungroup() %>%
select(-is.exit)
2) factorizar la condición Factorizar la condición convirtiéndola en una columna adicional que luego se elimina. Luego use ifelse, replaceo aritmética con lógicas como se ilustra. Esto también funciona para tablas de datos.
library(dplyr)
DF %>% mutate(is.exit = measure == 'exit',
qty.exit = ifelse(is.exit, qty, qty.exit),
cf = (!is.exit) * cf,
delta.watts = replace(delta.watts, is.exit, 13)) %>%
select(-is.exit)
3) sqldf Podríamos usar SQL a updatetravés del paquete sqldf en la canalización para marcos de datos (pero no tablas de datos a menos que las convirtamos; esto puede representar un error en dplyr. Consulte el número 1579 de dplyr ). Puede parecer que estamos modificando indeseablemente la entrada en este código debido a la existencia de updatepero, de hecho, updateestá actuando sobre una copia de la entrada en la base de datos generada temporalmente y no sobre la entrada real.
library(sqldf)
DF %>%
do(sqldf(c("update '.'
set 'qty.exit' = qty, cf = 0, 'delta.watts' = 13
where measure = 'exit'",
"select * from '.'")))
4) row_case_when También consulte row_case_whendefinido en
Devolver un tibble: ¿cómo vectorizar con case_when? . Utiliza una sintaxis similar case_whenpero se aplica a las filas.
library(dplyr)
DF %>%
row_case_when(
measure == "exit" ~ data.frame(qty.exit = qty, cf = 0, delta.watts = 13),
TRUE ~ data.frame(qty.exit, cf, delta.watts)
)
Nota 1: utilizamos esto comoDF
set.seed(1)
DF <- data.frame(site = sample(1:6, 50, replace=T),
space = sample(1:4, 50, replace=T),
measure = sample(c('cfl', 'led', 'linear', 'exit'), 50,
replace=T),
qty = round(runif(50) * 30),
qty.exit = 0,
delta.watts = sample(10.5:100.5, 50, replace=T),
cf = runif(50))
Nota 2: El problema de cómo especificar fácilmente la actualización de un subconjunto de filas también se discute en cuestiones dplyr 134 , 631 , 1518 y 1573 con 631 siendo el hilo principal y 1573 siendo un examen de las respuestas aquí.