I have a data set with many variables, two of which called "animal" and "plant". Both variable are factors, and both are binary, ie they are either a text value, or NA.
For example:
animal <- c(NA, NA, "cat", "cat", NA)
plant <- c("ivy", NA, "ivy", NA, NA)
value <- c(1:5)
df <- data.frame(animal, plant, value)
> df
animal plant value
1 <NA> ivy 1
2 <NA> <NA> 2
3 cat ivy 3
4 cat <NA> 4
5 <NA> <NA> 5
When the value of plant is "ivy" and the value of animal is "cat", I want to change the value of plant to NA (i,e, the two things can not be true and the animal value takes priority. I don't any changes in my other variables
I've tried the following but get an error message:
df <- df %>% if (isTRUE(animal == "cat")) {plant==NA}
Error in if (.) isTRUE(animal == "cat") else { :
argument is not interpretable as logical
In addition: Warning message:
In if (.) isTRUE(animal == "cat") else { :
the condition has length > 1 and only the first element will be used
My goal output is:
> df
animal plant value
1 <NA> ivy 1
2 <NA> <NA> 2
3 cat <NA> 3
4 cat <NA> 4
5 <NA> <NA> 5
I would really appreciate any help. I'm sure there is a really simple way of doing this, maybe I can't see the wood for the trees.
library(dplyr)
df %>%
mutate(plant = case_when(animal == 'cat' & plant == 'ivy' ~ NA_character_,
TRUE ~ plant))
This gives us:
animal plant value
1 <NA> ivy 1
2 <NA> <NA> 2
3 cat <NA> 3
4 cat <NA> 4
5 <NA> <NA> 5
You could also do:
df[!(is.na(df$animal)|is.na(df$plant)),'plant'] <- NA
df
animal plant value
1 <NA> ivy 1
2 <NA> <NA> 2
3 cat <NA> 3
4 cat <NA> 4
5 <NA> <NA> 5
This can also be expressed as:
df[!is.na(df$animal) & !is.na(df$plant),'plant'] <- NA
Your problem seems to be simpler than you think. You can achieve the same result simply by turning all plants, where animal is not NA
, to NA
:
df$plant[!is.na(df$animal)] <- NA
Or a bit fancier:
is.na(df$plant) <- !is.na(df$animal)
The problem here is that ==
does not work intuitively with the NA
values in R.
> df[df$animal=="cat",]
animal plant value
NA <NA> <NA> NA
NA.1 <NA> <NA> NA
3 cat ivy 3
4 cat <NA> 4
NA.2 <NA> <NA> NA
Here for example all lines are returned because NA == "ANYTHING"
returns NA
.
You could define this function which returns TRUE
if both x
and y
are equal and not NA
, or if both are NA
.
is.equal.force <- `%===%` <- function(x,y, vect=T) {
res <- ifelse(is.na(x),is.na(y),ifelse(!is.na(y)&!is.na(x),x==y, NA))
if(!vect){
res <- all(res)
}
return(res)
}
Then the solution to your problem becomes simply:
df[df$animal%===%"cat"&df$plant%===%"ivy","plant"] <- NA
df
animal plant value
1 <NA> ivy 1
2 <NA> <NA> 2
3 cat <NA> 3
4 cat <NA> 4
5 <NA> <NA> 5
Note that the correct syntax was used here.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.