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 mutate
ma 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 mutate
ma 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_by
specifica una condizione, mutate_last
funzionerà 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
, replace
o 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 update
tramite 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 update
ma in realtà update
sta 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_when
definita in
Restituzione di una tabella: come vettorializzare con case_when? . Usa una sintassi simile a case_when
ma 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.