Can the mutate be used when the mutation is conditional (depending on the values of certain column values)?
This example helps showing what I mean.
structure(list(a = c(1, 3, 4, 6, 3, 2, 5, 1), b = c(1, 3, 4,
2, 6, 7, 2, 6), c = c(6, 3, 6, 5, 3, 6, 5, 3), d = c(6, 2, 4,
5, 3, 7, 2, 6), e = c(1, 2, 4, 5, 6, 7, 6, 3), f = c(2, 3, 4,
2, 2, 7, 5, 2)), .Names = c("a", "b", "c", "d", "e", "f"), row.names = c(NA,
8L), class = "data.frame")
a b c d e f
1 1 1 6 6 1 2
2 3 3 3 2 2 3
3 4 4 6 4 4 4
4 6 2 5 5 5 2
5 3 6 3 3 6 2
6 2 7 6 7 7 7
7 5 2 5 2 6 5
8 1 6 3 6 3 2
I was hoping to find a solution to my problem using the dplyr package (and yes I know this not code that should work, but I guess it makes the purpose clear) for creating a new column g:
library(dplyr)
df <- mutate(df,
if (a == 2 | a == 5 | a == 7 | (a == 1 & b == 4)){g = 2},
if (a == 0 | a == 1 | a == 4 | a == 3 | c == 4) {g = 3})
The result of the code I am looking for should have this result in this particular example:
a b c d e f g
1 1 1 6 6 1 2 3
2 3 3 3 2 2 3 3
3 4 4 6 4 4 4 3
4 6 2 5 5 5 2 NA
5 3 6 3 3 6 2 NA
6 2 7 6 7 7 7 2
7 5 2 5 2 6 5 2
8 1 6 3 6 3 2 3
Does anyone have an idea about how to do this in dplyr? This data frame is just an example, the data frames I am dealing with are much larger. Because of its speed I tried to use dplyr, but perhaps there are other, better ways to handle this problem?
Since you ask for other better ways to handle the problem, here's another way using
data.table
:Note the order of conditional statements is reversed to get
g
correctly. There's no copy ofg
made, even during the second assignment - it's replaced in-place.On larger data this would have better performance than using nested
if-else
, as it can evaluate both 'yes' and 'no' cases, and nesting can get harder to read/maintain IMHO.Here's a benchmark on relatively bigger data:
Not sure if this is an alternative you'd asked for, but I hope it helps.
Use
ifelse
Added - if_else: Note that in dplyr 0.5 there is an
if_else
function defined so an alternative would be to replaceifelse
withif_else
; however, note that sinceif_else
is stricter thanifelse
(both legs of the condition must have the same type) so theNA
in that case would have to be replaced withNA_real_
.Added - case_when Since this question was posted dplyr has added
case_when
so another alternative would be:case_when
is now a pretty clean implementation of the SQL-style case when:Using dplyr 0.7.4
The manual: http://dplyr.tidyverse.org/reference/case_when.html
dplyr now has a function
case_when
that offers a vectorised if. The syntax is a little strange compared tomosaic:::derivedFactor
as you cannot access variables in the standard dplyr way, and need to declare the mode of NA, but it is considerably faster thanmosaic:::derivedFactor
.EDIT: If you're using
dplyr::case_when()
from before version 0.7.0 of the package, then you need to precede variable names with '.$
' (e.g. write.$a == 1
insidecase_when
).Benchmark: For the benchmark (reusing functions from Arun 's post) and reducing sample size:
This gives:
The
derivedFactor
function frommosaic
package seems to be designed to handle this. Using this example, it would look like:(If you want the result to be numeric instead of a factor, you can wrap
derivedFactor
in anas.numeric
call.)derivedFactor
can be used for an arbitrary number of conditionals, too.