dplyr mutiert / ersetzt mehrere Spalten in einer Teilmenge von Zeilen

85

Ich bin gerade dabei, einen dplyr-basierten Workflow auszuprobieren (anstatt hauptsächlich data.table zu verwenden, wie ich es gewohnt bin), und bin auf ein Problem gestoßen, für das ich keine entsprechende dplyr-Lösung finden kann . Ich stoße normalerweise auf das Szenario, in dem ich mehrere Spalten basierend auf einer einzelnen Bedingung bedingt aktualisieren / ersetzen muss. Hier ist ein Beispielcode mit meiner data.table-Lösung:

library(data.table)

# Create some sample data
set.seed(1)
dt <- data.table(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))

# Replace the values of several columns for rows where measure is "exit"
dt <- dt[measure == 'exit', 
         `:=`(qty.exit = qty,
              cf = 0,
              delta.watts = 13)]

Gibt es eine einfache dplyr-Lösung für dasselbe Problem? Ich möchte die Verwendung von ifelse vermeiden, da ich die Bedingung nicht mehrmals eingeben muss - dies ist ein vereinfachtes Beispiel, aber manchmal gibt es viele Zuweisungen, die auf einer einzelnen Bedingung basieren.

Vielen Dank im Voraus für die Hilfe!

Chris Newton
quelle

Antworten:

80

Diese Lösungen (1) hält die Rohrleitung (2) noch nicht überschreiben , die Eingabe und (3) nur erfordert , dass die Bedingung einmal spezifiziert werden:

1a) mutate_cond Erstellen Sie eine einfache Funktion für Datenrahmen oder Datentabellen, die in Pipelines integriert werden können. Diese Funktion ist wie mutate, wirkt jedoch nur auf die Zeilen, die die Bedingung erfüllen:

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 Dies ist eine alternative Funktion für Datenrahmen oder Datentabellen, die wiederum ähnlich ist, mutateaber nur innerhalb group_by(wie im folgenden Beispiel) verwendet wird und nur für die letzte Gruppe und nicht für jede Gruppe ausgeführt wird. Beachten Sie, dass TRUE> FALSE. Wenn Sie also group_byeine Bedingung angeben, mutate_lastwerden nur Zeilen bearbeitet, die diese Bedingung erfüllen.

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) Bedingung ausklammern Die Bedingung ausklammern, indem sie zu einer zusätzlichen Spalte gemacht wird, die später entfernt wird. Dann verwenden ifelse, replaceoder Arithmetik mit Logicals wie dargestellt. Dies funktioniert auch für Datentabellen.

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 Wir könnten SQL updateüber das sqldf-Paket in der Pipeline für Datenrahmen verwenden (aber keine Datentabellen, es sei denn, wir konvertieren sie - dies könnte einen Fehler in dplyr darstellen. Siehe dplyr-Ausgabe 1579 ). Es mag den Anschein haben, als würden wir die Eingabe in diesem Code unerwünscht ändern, da das vorhanden ist, updateaber tatsächlich updatewirkt sich dies auf eine Kopie der Eingabe in der vorübergehend generierten Datenbank und nicht auf die tatsächliche Eingabe aus.

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 Überprüfen Sie auch, row_case_whenwie unter Zurückgeben eines Tibbles definiert: Wie wird mit case_when vektorisiert? . Es verwendet eine Syntax ähnlich der case_when, gilt jedoch für Zeilen.

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)
  )

Anmerkung 1: Wir haben dies als verwendetDF

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))

Anmerkung 2: Das Problem, wie die Aktualisierung einer Teilmenge von Zeilen einfach angegeben werden kann, wird auch in den dplyr-Ausgaben 134 , 631 , 1518 und 1573 erörtert , wobei 631 der Hauptthread und 1573 eine Überprüfung der Antworten hier ist.

G. Grothendieck
quelle
1
Hervorragende Antwort, danke! Ihre mutate_cond und @Kevin Usheys mutate_when sind beide gute Lösungen für dieses Problem. Ich glaube, ich habe eine leichte Vorliebe für die Lesbarkeit / Flexibilität von mutate_when, aber ich werde dieser Antwort die "Prüfung" auf Gründlichkeit geben.
Chris Newton
Ich mag den mutate_cond-Ansatz sehr. Mir scheint, dass diese Funktion oder etwas sehr Nahes in dplyr enthalten ist und eine bessere Lösung als VectorizedSwitch (das wird in github.com/hadley/dplyr/issues/1573 beschrieben ) für den Anwendungsfall ist, den die Leute denken ungefähr hier ...
Magnus
Ich liebe mutate_cond. Die verschiedenen Optionen sollten separate Antworten gewesen sein.
Holger Brandl
Es ist ein paar Jahre her und die Github-Probleme scheinen geschlossen und verschlossen zu sein. Gibt es eine offizielle Lösung für dieses Problem?
static_rtti
27

Sie können dies mit magrittrder Zweiwege-Leitung tun %<>%:

library(dplyr)
library(magrittr)

dt[dt$measure=="exit",] %<>% mutate(qty.exit = qty,
                                    cf = 0,  
                                    delta.watts = 13)

Dies reduziert den Schreibaufwand, ist aber immer noch viel langsamer als data.table.

eipi10
quelle
Jetzt, da ich die Möglichkeit hatte, dies zu testen, würde ich eine Lösung bevorzugen, die die Notwendigkeit einer Teilmenge mit der Notation dt [dt $ Measure == 'exit',] vermeidet, da dies mit längerer Zeit unhandlich werden kann dt Namen.
Chris Newton
Nur zu Ihrer Information, aber diese Lösung funktioniert nur, wenn das data.frame/ tibblebereits die durch definierte Spalte enthält mutate. Es funktioniert nicht, wenn Sie versuchen, eine neue Spalte hinzuzufügen, z. B. wenn Sie zum ersten Mal eine Schleife durchlaufen und a ändern data.frame.
Ursus Frost
@UrsusFrost Das Hinzufügen einer neuen Spalte, die nur eine Teilmenge des Datensatzes ist, erscheint mir seltsam. Sie fügen NA zu Zeilen hinzu, die nicht untergeordnet sind?
Baraliuh
@ Baraliuh Ja, das kann ich schätzen. Es ist Teil einer Schleife, in der ich Daten über eine Liste von Daten inkrementiere und anhänge. Die ersten Daten müssen anders behandelt werden als die nachfolgenden Daten, da sie reale Geschäftsprozesse replizieren. In weiteren Iterationen werden die Daten abhängig von den Bedingungen der Daten unterschiedlich berechnet. Aufgrund der Konditionalität möchte ich nicht versehentlich frühere Daten in der ändern data.frame. FWIW, ich habe gerade wieder verwendet, data.tableanstatt, dplyrweil sein iAusdruck dies leicht handhabt - und die gesamte Schleife läuft viel schneller.
Ursus Frost
18

Hier ist eine Lösung, die mir gefällt:

mutate_when <- function(data, ...) {
  dots <- eval(substitute(alist(...)))
  for (i in seq(1, length(dots), by = 2)) {
    condition <- eval(dots[[i]], envir = data)
    mutations <- eval(dots[[i + 1]], envir = data[condition, , drop = FALSE])
    data[condition, names(mutations)] <- mutations
  }
  data
}

Damit können Sie Dinge wie z

mtcars %>% mutate_when(
  mpg > 22,    list(cyl = 100),
  disp == 160, list(cyl = 200)
)

Das ist gut lesbar - obwohl es möglicherweise nicht so performant ist, wie es sein könnte.

Kevin Ushey
quelle
14

Wie eipi10 oben zeigt, gibt es keine einfache Möglichkeit, eine Teilmenge in dplyr zu ersetzen, da DT die Referenz-Pass-Semantik und dplyr die Pass-By-Wert-Semantik verwendet. dplyr erfordert die Verwendung des ifelse()gesamten Vektors, während DT die Teilmenge ausführt und durch Referenz aktualisiert (Rückgabe des gesamten DT). In dieser Übung ist DT also wesentlich schneller.

Sie können alternativ zuerst eine Teilmenge erstellen, dann aktualisieren und schließlich neu kombinieren:

dt.sub <- dt[dt$measure == "exit",] %>%
  mutate(qty.exit= qty, cf= 0, delta.watts= 13)

dt.new <- rbind(dt.sub, dt[dt$measure != "exit",])

Aber DT wird wesentlich schneller sein: (bearbeitet, um die neue Antwort von eipi10 zu verwenden)

library(data.table)
library(dplyr)
library(microbenchmark)
microbenchmark(dt= {dt <- dt[measure == 'exit', 
                            `:=`(qty.exit = qty,
                                 cf = 0,
                                 delta.watts = 13)]},
               eipi10= {dt[dt$measure=="exit",] %<>% mutate(qty.exit = qty,
                                cf = 0,  
                                delta.watts = 13)},
               alex= {dt.sub <- dt[dt$measure == "exit",] %>%
                 mutate(qty.exit= qty, cf= 0, delta.watts= 13)

               dt.new <- rbind(dt.sub, dt[dt$measure != "exit",])})


Unit: microseconds
expr      min        lq      mean   median       uq      max neval cld
     dt  591.480  672.2565  747.0771  743.341  780.973 1837.539   100  a 
 eipi10 3481.212 3677.1685 4008.0314 3796.909 3936.796 6857.509   100   b
   alex 3412.029 3637.6350 3867.0649 3726.204 3936.985 5424.427   100   b
Alex W.
quelle
10

Ich bin nur darüber gestolpert und mag es wirklich mutate_cond() @G . Grothendieck, dachte aber, es könnte nützlich sein, auch mit neuen Variablen umzugehen. Im Folgenden finden Sie zwei Ergänzungen:

Ohne Bezug: Zweite letzte Zeile aus einem wenig mehr dplyrdurch die Verwendungfilter()

Drei neue Zeilen am Anfang erhalten Variablennamen zur Verwendung in mutate()und initialisieren alle neuen Variablen im Datenrahmen, bevor sie mutate()auftreten. Für den Rest der data.frameVerwendung werden neue Variablen initialisiert new_init, die NAstandardmäßig auf missing ( ) gesetzt sind.

mutate_cond <- function(.data, condition, ..., new_init = NA, envir = parent.frame()) {
  # Initialize any new variables as new_init
  new_vars <- substitute(list(...))[-1]
  new_vars %<>% sapply(deparse) %>% names %>% setdiff(names(.data))
  .data[, new_vars] <- new_init

  condition <- eval(substitute(condition), .data, envir)
  .data[condition, ] <- .data %>% filter(condition) %>% mutate(...)
  .data
}

Hier einige Beispiele unter Verwendung der Irisdaten:

Wechseln Sie Petal.Lengthzu 88 wo Species == "setosa". Dies funktioniert sowohl in der ursprünglichen Funktion als auch in dieser neuen Version.

iris %>% mutate_cond(Species == "setosa", Petal.Length = 88)

Wie oben, aber auch eine neue Variable erstellen x( NAin Zeilen, die nicht in der Bedingung enthalten sind). Vorher nicht möglich.

iris %>% mutate_cond(Species == "setosa", Petal.Length = 88, x = TRUE)

Wie oben, jedoch werden Zeilen, die nicht in der Bedingung für enthalten xsind, auf FALSE gesetzt.

iris %>% mutate_cond(Species == "setosa", Petal.Length = 88, x = TRUE, new_init = FALSE)

Dieses Beispiel zeigt, wie auf a gesetzt werden new_initkann list, um mehrere neue Variablen mit unterschiedlichen Werten zu initialisieren. Hier werden zwei neue Variablen erstellt, wobei ausgeschlossene Zeilen mit unterschiedlichen Werten xinitialisiert werden ( initialisiert als FALSE, yas NA).

iris %>% mutate_cond(Species == "setosa" & Sepal.Length < 5,
                  x = TRUE, y = Sepal.Length ^ 2,
                  new_init = list(FALSE, NA))
Simon Jackson
quelle
Ihre mutate_condFunktion löscht einen Fehler in meinem Datensatz und die Funktion von Grothendiecks nicht. Error: incorrect length (4700), expecting: 168Scheint mit der Filterfunktion verbunden zu sein.
RHA
Haben Sie dies in eine Bibliothek gestellt oder als Funktion formalisiert? Es scheint ein Kinderspiel zu sein, besonders bei all den Verbesserungen.
Brennnessel
1
Nein. Ich denke, der beste Ansatz mit dplyr ist derzeit, Mutation mit if_elseoder zu kombinieren case_when.
Simon Jackson
Können Sie ein Beispiel (oder einen Link) zu diesem Ansatz angeben?
Brennnessel
6

mutate_cond ist eine großartige Funktion, gibt jedoch einen Fehler aus, wenn in den Spalten, die zum Erstellen der Bedingung verwendet werden, eine NA vorhanden ist. Ich bin der Meinung, dass eine bedingte Mutation solche Zeilen einfach in Ruhe lassen sollte. Dies entspricht dem Verhalten von filter (), das Zeilen zurückgibt, wenn die Bedingung TRUE ist, aber beide Zeilen mit FALSE und NA weglässt.

Mit dieser kleinen Änderung wirkt die Funktion wie ein Zauber:

mutate_cond <- function(.data, condition, ..., envir = parent.frame()) {
    condition <- eval(substitute(condition), .data, envir)
    condition[is.na(condition)] = FALSE
    .data[condition, ] <- .data[condition, ] %>% mutate(...)
    .data
}
Magnus
quelle
Danke Magnus! Ich verwende dies, um eine Tabelle mit Aktionen und Timings für alle Objekte zu aktualisieren, aus denen eine Animation besteht. Ich bin auf das NA-Problem gestoßen, weil die Daten so unterschiedlich sind, dass einige Aktionen für einige Objekte keinen Sinn ergeben. Daher habe ich NAs in diesen Zellen. Die andere mutate_cond oben ist abgestürzt, aber Ihre Lösung hat wie ein Zauber funktioniert.
Phil van Kleur
Wenn dies für Sie nützlich ist, ist diese Funktion in einem kleinen Paket verfügbar, das ich geschrieben habe: "zulutils". Es ist nicht auf CRAN, aber Sie können es mit remotes :: install_github ("torfason / zulutils") installieren
Magnus
Toll! Danke vielmals. Ich benutze es immer noch.
Phil van Kleur
4

Ich sehe eigentlich keine Änderungen daran dplyr, die dies viel einfacher machen würden. case_whenDies ist ideal, wenn für eine Spalte mehrere unterschiedliche Bedingungen und Ergebnisse vorliegen. In diesem Fall, in dem Sie mehrere Spalten basierend auf einer Bedingung ändern möchten, ist dies jedoch nicht hilfreich. In ähnlicher Weise wird die recodeEingabe gespeichert, wenn Sie mehrere verschiedene Werte in einer Spalte ersetzen, dies jedoch nicht in mehreren Spalten gleichzeitig hilft. Schließlich,mutate_at wenden Sie Bedingungen nur auf die Spaltennamen an, nicht auf die Zeilen im Datenrahmen. Sie könnten möglicherweise eine Funktion für mutate_at schreiben, die dies tun würde, aber ich kann nicht herausfinden, wie Sie dafür sorgen würden, dass es sich für verschiedene Spalten unterschiedlich verhält.

Das heißt, hier ist, wie ich es mit nestForm tidyrund mapvon nähern würde purrr.

library(data.table)
library(dplyr)
library(tidyr)
library(purrr)

# Create some sample data
set.seed(1)
dt <- data.table(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))

dt2 <- dt %>% 
  nest(-measure) %>% 
  mutate(data = if_else(
    measure == "exit", 
    map(data, function(x) mutate(x, qty.exit = qty, cf = 0, delta.watts = 13)),
    data
  )) %>%
  unnest()
see24
quelle
1
Das einzige, was ich vorschlagen würde, ist zu verwenden nest(-measure), um diegroup_by
Dave Gruenewald
Bearbeitet, um @ DaveGruenewald Vorschlag zu reflektieren
siehe24
4

Eine prägnante Lösung wäre, die Mutation für die gefilterte Teilmenge durchzuführen und dann die Non-Exit-Zeilen der Tabelle wieder hinzuzufügen:

library(dplyr)

dt %>% 
    filter(measure == 'exit') %>%
    mutate(qty.exit = qty, cf = 0, delta.watts = 13) %>%
    rbind(dt %>% filter(measure != 'exit'))
Bob Zimmermann
quelle
3

Mit der Erstellung von rlangist eine leicht modifizierte Version des Beispiels 1a von Grothendieck möglich, sodass das envirArgument nicht mehr benötigt wird, da enquo()die Umgebung .perstellt wird, in der automatisch erstellt wird.

mutate_rows <- function(.data, .p, ...) {
  .p <- rlang::enquo(.p)
  .p_lgl <- rlang::eval_tidy(.p, .data)
  .data[.p_lgl, ] <- .data[.p_lgl, ] %>% mutate(...)
  .data
}

dt %>% mutate_rows(measure == "exit", qty.exit = qty, cf = 0, delta.watts = 13)
Davis Vaughan
quelle
2

Sie können den Datensatz aufteilen und das TRUETeil regelmäßig mutieren .

dplyr 0.8 bietet die Funktion, group_splitdie nach Gruppen aufgeteilt wird (und Gruppen können direkt im Aufruf definiert werden), sodass wir sie hier verwenden, aber auch base::splitfunktionieren.

library(tidyverse)
df1 %>%
  group_split(measure == "exit", keep=FALSE) %>% # or `split(.$measure == "exit")`
  modify_at(2,~mutate(.,qty.exit = qty, cf = 0, delta.watts = 13)) %>%
  bind_rows()

#    site space measure qty qty.exit delta.watts          cf
# 1     1     4     led   1        0        73.5 0.246240409
# 2     2     3     cfl  25        0        56.5 0.360315879
# 3     5     4     cfl   3        0        38.5 0.279966850
# 4     5     3  linear  19        0        40.5 0.281439486
# 5     2     3  linear  18        0        82.5 0.007898384
# 6     5     1  linear  29        0        33.5 0.392412729
# 7     5     3  linear   6        0        46.5 0.970848817
# 8     4     1     led  10        0        89.5 0.404447182
# 9     4     1     led  18        0        96.5 0.115594622
# 10    6     3  linear  18        0        15.5 0.017919745
# 11    4     3     led  22        0        54.5 0.901829577
# 12    3     3     led  17        0        79.5 0.063949974
# 13    1     3     led  16        0        86.5 0.551321441
# 14    6     4     cfl   5        0        65.5 0.256845013
# 15    4     2     led  12        0        29.5 0.340603733
# 16    5     3  linear  27        0        63.5 0.895166931
# 17    1     4     led   0        0        47.5 0.173088800
# 18    5     3  linear  20        0        89.5 0.438504370
# 19    2     4     cfl  18        0        45.5 0.031725246
# 20    2     3     led  24        0        94.5 0.456653397
# 21    3     3     cfl  24        0        73.5 0.161274319
# 22    5     3     led   9        0        62.5 0.252212124
# 23    5     1     led  15        0        40.5 0.115608182
# 24    3     3     cfl   3        0        89.5 0.066147321
# 25    6     4     cfl   2        0        35.5 0.007888337
# 26    5     1  linear   7        0        51.5 0.835458916
# 27    2     3  linear  28        0        36.5 0.691483644
# 28    5     4     led   6        0        43.5 0.604847889
# 29    6     1  linear  12        0        59.5 0.918838163
# 30    3     3  linear   7        0        73.5 0.471644760
# 31    4     2     led   5        0        34.5 0.972078100
# 32    1     3     cfl  17        0        80.5 0.457241602
# 33    5     4  linear   3        0        16.5 0.492500255
# 34    3     2     cfl  12        0        44.5 0.804236607
# 35    2     2     cfl  21        0        50.5 0.845094268
# 36    3     2  linear  10        0        23.5 0.637194873
# 37    4     3     led   6        0        69.5 0.161431896
# 38    3     2    exit  19       19        13.0 0.000000000
# 39    6     3    exit   7        7        13.0 0.000000000
# 40    6     2    exit  20       20        13.0 0.000000000
# 41    3     2    exit   1        1        13.0 0.000000000
# 42    2     4    exit  19       19        13.0 0.000000000
# 43    3     1    exit  24       24        13.0 0.000000000
# 44    3     3    exit  16       16        13.0 0.000000000
# 45    5     3    exit   9        9        13.0 0.000000000
# 46    2     3    exit   6        6        13.0 0.000000000
# 47    4     1    exit   1        1        13.0 0.000000000
# 48    1     1    exit  14       14        13.0 0.000000000
# 49    6     3    exit   7        7        13.0 0.000000000
# 50    2     4    exit   3        3        13.0 0.000000000

Wenn die Zeilenreihenfolge wichtig ist, verwenden Sie tibble::rowid_to_columnzuerst, dann dplyr::arrangeein rowidund wählen Sie sie am Ende aus.

Daten

df1 <- 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),
                 stringsAsFactors = F)
Moody_Mudskipper
quelle
2

Ich denke, diese Antwort wurde noch nicht erwähnt. Es läuft fast so schnell wie die 'Standard'- data.tableLösung.

Verwenden base::replace()

df %>% mutate( qty.exit = replace( qty.exit, measure == 'exit', qty[ measure == 'exit'] ),
                          cf = replace( cf, measure == 'exit', 0 ),
                          delta.watts = replace( delta.watts, measure == 'exit', 13 ) )

Ersetzen recycelt den Ersetzungswert. Wenn Sie also die Werte von Spalten qtyin Spalten eingeben möchten qty.exit, müssen Sie auch eine Teilmenge festlegen qty ... daher die qty[ measure == 'exit']beim ersten Ersetzen.

Jetzt möchten Sie wahrscheinlich nicht die measure == 'exit'ganze Zeit neu eingeben ... also können Sie einen Indexvektor erstellen, der diese Auswahl enthält, und ihn in den obigen Funktionen verwenden.

#build an index-vector matching the condition
index.v <- which( df$measure == 'exit' )

df %>% mutate( qty.exit = replace( qty.exit, index.v, qty[ index.v] ),
               cf = replace( cf, index.v, 0 ),
               delta.watts = replace( delta.watts, index.v, 13 ) )

Benchmarks

# Unit: milliseconds
#         expr      min       lq     mean   median       uq      max neval
# data.table   1.005018 1.053370 1.137456 1.112871 1.186228 1.690996   100
# wimpel       1.061052 1.079128 1.218183 1.105037 1.137272 7.390613   100
# wimpel.index 1.043881 1.064818 1.131675 1.085304 1.108502 4.192995   100
Wimpel
quelle
1

Auf Kosten der Verletzung der üblichen dplyr-Syntax können Sie withinvon base aus Folgendes verwenden :

dt %>% within(qty.exit[measure == 'exit'] <- qty[measure == 'exit'],
              delta.watts[measure == 'exit'] <- 13)

Es scheint sich gut in die Pipe zu integrieren, und Sie können so ziemlich alles tun, was Sie wollen.

Jan Hlavacek
quelle
Dies funktioniert nicht wie geschrieben, da die zweite Zuweisung nicht tatsächlich erfolgt. Aber wenn Sie das tun, dt %>% within({ delta.watts[measure == 'exit'] <- 13 ; qty.exit[measure == 'exit'] <- qty[measure == 'exit'] ; cf[measure == 'exit'] <- 0 })dann funktioniert es
siehe 24.