Te rozwiązania (1) utrzymują potok, (2) nie nadpisują danych wejściowych i (3) wymagają tylko jednorazowego określenia warunku:
1a) mutate_cond Utwórz prostą funkcję dla ramek danych lub tabel danych, które można włączyć do potoków. Ta funkcja jest podobna, mutate
ale działa tylko na wierszach spełniających warunek:
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 Jest to alternatywna funkcja dla ramek danych lub tabel danych, która również jest podobna, mutate
ale jest używana tylko w obrębie group_by
(jak w poniższym przykładzie) i działa tylko na ostatniej grupie, a nie na każdej grupie. Zauważ, że TRUE> FALSE, więc jeśli group_by
określi warunek, mutate_last
będzie działać tylko na wierszach spełniających ten warunek.
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) Uwzględnij warunek Uwzględnij warunek, tworząc dodatkową kolumnę, która jest później usuwana. Następnie za pomocą ifelse
, replace
lub arytmetyczne logicals jak pokazano na rysunku. Działa to również w przypadku tabel danych.
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 Moglibyśmy użyć SQL update
za pośrednictwem pakietu sqldf w potoku dla ramek danych (ale nie tabel danych, chyba że je przekonwertujemy - może to oznaczać błąd w dplyr. Zobacz dplyr wydanie 1579 ). Może się wydawać, że niepożądanie modyfikujemy dane wejściowe w tym kodzie ze względu na istnienie, update
ale w rzeczywistości update
działa na kopii danych wejściowych w tymczasowo wygenerowanej bazie danych, a nie na faktycznych danych wejściowych.
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 Sprawdź również row_case_when
zdefiniowane w
sekcji Zwracanie tibble: jak wektoryzować za pomocą case_when? . Używa składni podobnej case_when
do wierszy, ale ma zastosowanie do.
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)
)
Uwaga 1: Użyliśmy tego jakoDF
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))
Uwaga 2: Problem łatwego określania aktualizacji podzbioru wierszy jest również omawiany w wydaniach dplyr 134 , 631 , 1518 i 1573, gdzie 631 jest głównym tematem , a 1573 jest przeglądem odpowiedzi tutaj.