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 mutate
pero 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 mutate
pero 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_by
especifica 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
, replace
o 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 update
travé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 update
pero, de hecho, update
está 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_when
definido en
Devolver un tibble: ¿cómo vectorizar con case_when? . Utiliza una sintaxis similar case_when
pero 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í.