Эти решения (1) поддерживают конвейер, (2) не перезаписывают входные данные и (3) требуют, чтобы условие было указано только один раз:
1a) mutate_cond Создайте простую функцию для фреймов данных или таблиц данных, которые могут быть включены в конвейеры. Эта функция похожа, mutate
но действует только на строки, удовлетворяющие условию:
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 Это альтернативная функция для фреймов данных или таблиц данных, которая снова похожа, mutate
но используется только внутри group_by
(как в примере ниже) и работает только с последней группой, а не с каждой группой. Обратите внимание, что TRUE> FALSE, поэтому if group_by
указывает условие, тогда mutate_last
будет работать только со строками, удовлетворяющими этому условию.
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) исключить условие Фактор условия, сделав его дополнительным столбцом, который позже удаляется. Затем используйте ifelse
, replace
или арифметику с логикой, как показано. Это также работает для таблиц данных.
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. Мы могли бы использовать SQL update
через пакет sqldf в конвейере для фреймов данных (но не таблиц данных, если мы их не конвертируем - это может представлять ошибку в dplyr. См. Dplyr issue 1579 ). Может показаться, что мы нежелательно изменяем ввод в этом коде из-за существования, update
но на самом деле update
он действует на копию ввода во временно сгенерированной базе данных, а не на фактический ввод.
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 Также ознакомьтесь с row_case_when
определением в
разделе «Возврат тиббла»: как векторизовать с помощью case_when? . Он использует синтаксис, аналогичный, case_when
но применяется к строкам.
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)
)
Примечание 1: мы использовали это какDF
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))
Примечание 2: проблема того, как легко указать обновление подмножества строк, также обсуждается в вопросах 134 , 631 , 1518 и 1573 dplyr , где 631 является основным потоком, а 1573 является обзором ответов здесь.