Queste soluzioni (1) mantengono la pipeline, (2) non sovrascrivono l'input e (3) richiedono solo che la condizione sia specificata una volta:
1a) mutate_cond Crea una semplice funzione per frame di dati o tabelle di dati che possono essere incorporati nelle pipeline. Questa funzione è simile mutatema agisce solo sulle righe che soddisfano la condizione:
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 Questa è una funzione alternativa per i frame di dati o le tabelle di dati che di nuovo è simile mutatema viene utilizzata solo all'interno group_by(come nell'esempio sotto) e opera solo sull'ultimo gruppo piuttosto che su ogni gruppo. Notare che TRUE> FALSE quindi se group_byspecifica una condizione, mutate_lastfunzionerà solo sulle righe che soddisfano quella condizione.
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) Fattorizzare la condizione Fattorizzare la condizione rendendola una colonna aggiuntiva che verrà successivamente rimossa. Quindi usa ifelse, replaceo aritmetica con logiche come illustrato. Questo funziona anche per le tabelle di dati.
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 Potremmo usare SQL updatetramite il pacchetto sqldf nella pipeline per i frame di dati (ma non le tabelle di dati a meno che non li convertiamo - questo potrebbe rappresentare un bug in dplyr. Vedi dplyr problema 1579 ). Può sembrare che stiamo modificando indesiderabilmente l'input in questo codice a causa dell'esistenza del updatema in realtà updatesta agendo su una copia dell'input nel database generato temporaneamente e non sull'input effettivo.
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 Verifica anche row_case_whendefinita in
Restituzione di una tabella: come vettorializzare con case_when? . Usa una sintassi simile a case_whenma si applica alle righe.
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: abbiamo usato questo fileDF
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: Il problema di come specificare facilmente l'aggiornamento di un sottoinsieme di righe è discusso anche nei numeri 134 , 631 , 1518 e 1573 di dplyr con 631 come thread principale e 1573 come revisione delle risposte qui.