In a large dataframe ("myfile") with four columns I have to add a fifth column with values conditonally based on the first four columns. Recently I have become a huge fan of dplyr, mainly because of its speed in large datasets. So I was wondering if I could deal with my problem using the mutate function.
My dataframe (actually a shorter version of it) looks a bit like this:
V1 V2 V3 V4
1 1 2 3 5
2 2 4 4 1
3 1 4 1 1
4 4 5 1 3
5 5 5 5 4
The values of the fifth column (V5) are based on some conditional rules:
if (V1==1 & V2!=4){
V5 <- 1
}
else if (V2==4 & V3!=1){
V5 <- 2
}
else {
V5 <- 0
}
Now I want to use the mutate function to use these rules on all rows (so I don't have to use a slow loop). Something like this (and yes, I know it doesn't work this way!):
myfile <- mutate(myfile, if (V1==1 & V2!=4){V5 = 1}
else if (V2==4 & V3!=1){V5 = 2}
else {V5 = 0})
This should be the result:
V1 V2 V3 V4 V5
1 1 2 3 5 1
2 2 4 4 1 2
3 1 4 1 1 0
4 4 5 1 3 0
5 5 5 5 4 0
How to do this in dplyr
?
Try this:
giving:
or this:
giving:
Suggest you get a better name for your data frame. myfile makes it seem as if it holds a file name.
Above used this input:
Update 1 Since originally posted dplyr has changed
%.%
to%>%
so have modified answer accordingly.Update 2 dplyr now has
case_when
which provides another solution:With
dplyr 0.7.2
, you can use the very usefulcase_when
function :Expressed with
dplyr::mutate
, it gives:Please note that
NA
are not treated specially, as it can be misleading. The function will returnNA
only when no condition is matched. If you put a line withTRUE ~ ...
, like I did in my example, the return value will then never beNA
.Therefore, you have to expressively tell
case_when
to putNA
where it belongs by adding a statement likeis.na(x$V1) | is.na(x$V3) ~ NA_integer_
. Hint: thedplyr::coalesce()
function can be really useful here sometimes!Moreover, please note that
NA
alone will usually not work, you have to put specialNA
values :NA_integer_
,NA_character_
orNA_real_
.It looks like
derivedFactor
from themosaic
package was designed for this. In this example, it would look something like:(If you want the outcome to be numeric instead of a factor, wrap the
derivedFactor
with anas.numeric
.)Note that the
.default
option combined with.method = "first"
sets the "else" condition -- this approach is described in the help file forderivedFactor
.