Essas soluções (1) mantêm o pipeline, (2) não substituem a entrada e (3) exigem apenas que a condição seja especificada uma vez:
1a) mutate_cond Crie uma função simples para frames de dados ou tabelas de dados que podem ser incorporados em pipelines. Esta função é semelhante, mutate
mas age apenas nas linhas que satisfazem a condição:
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 é uma função alternativa para quadros de dados ou tabelas de dados que são semelhantes, mutate
mas são usados apenas dentro group_by
(como no exemplo abaixo) e só opera no último grupo ao invés de todos os grupos. Observe que TRUE> FALSE, portanto, se group_by
especifica uma condição, mutate_last
só operará em linhas que satisfaçam essa condição.
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) fatorar a condição Fatorar a condição tornando-a uma coluna extra que é posteriormente removida. Em seguida ifelse
, use replace
ou aritmética com lógica, conforme ilustrado. Isso também funciona para tabelas de dados.
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 Poderíamos usar SQL update
por meio do pacote sqldf no pipeline para quadros de dados (mas não tabelas de dados, a menos que os convertamos - isso pode representar um bug no dplyr. Veja o problema 1579 do dplyr ). Pode parecer que estamos modificando indesejavelmente a entrada neste código devido à existência do, update
mas na verdade o update
está agindo em uma cópia da entrada no banco de dados gerado temporariamente e não na 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 Verifique também row_case_when
definido em
Retornando uma tabela: como vetorizar com case_when? . Ele usa uma sintaxe semelhante a, case_when
mas se aplica a linhas.
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: Usamos isso 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: O problema de como especificar facilmente a atualização de um subconjunto de linhas também é discutido nas questões de dplyr 134 , 631 , 1518 e 1573, com 631 sendo o thread principal e 1573 sendo uma revisão das respostas aqui.