29

With the following sample data I'm trying to create a new variable "Den" (value "0" or "1") based on the values of three conditional variables (Denial1, Denial2, and Denial3).

I want a "0" if ANY of the three conditional variables has a "0" and a "1" only if EACH conditional variable that has a value in it has a value of "1" (e.g., isn't NA).

structure(list(Denial1 = NA_real_, Denial2 = 1, Denial3 = NA_real_, 
Den = NA), .Names = c("Denial1", "Denial2", "Denial3", "Den"
), row.names = 1L, class = "data.frame")

I've tried both of the following commands that result in a missing value NA for "Den":

DF$Den<-ifelse (DF$Denial1 < 1 | DF$Denial2 < 1 | DF$Denial3 < 1, "0", "1")

DF$Den<-ifelse(DF$Denial1 < 1,"0", ifelse (DF$Denial2 < 1,"0", ifelse(DF$Denial3 < 1,"0", "1")))

Could someone demonstrate how to do this?

user3594490
  • 1,949
  • 2
  • 20
  • 26
  • 1
    possibly helpful: http://stackoverflow.com/questions/18012222/nested-ifelse-statement-in-r?rq=1 – jaimedash Apr 01 '16 at 17:46
  • 1
    @jaimedash thank you for the link, I did read that before I posted the question and included the script for nested ifelse statements above. I must still be making an error somewhere. – user3594490 Apr 01 '16 at 17:58
  • you need both 1) not `NA` and 2) `< 1`. It's ugly, but chaining several of these `(DF$Denial1 < 1 & !is.na(DF$Denial1) )` with `&` should work. (Edited to change from `&&` to elementwise `&`) – jaimedash Apr 01 '16 at 18:08
  • @jaimedash Many thanks that works and it's ugly! – user3594490 Apr 01 '16 at 18:25
  • awesome. you should post the working ugliness as an answer – jaimedash Apr 01 '16 at 18:29
  • Is your question worded incorrectly? You say you want a 1 'only if EACH conditional variable that has a value in it has a value of "1" (e.g., isn't NA)'. Doesn't this mean *all* of the values need to be 1 in order for *Den* to be 1? However, your answer (and apparently what you really want) is for *Den* to be 1 if *any* of *Denial1*, *Denial2*, or *Denial3* are 1. – Meg Nov 30 '18 at 00:48

5 Answers5

33

Based on suggestions from @jaimedash and @Old_Mortality I found a solution:

DF$Den <- ifelse(DF$Denial1 < 1 & !is.na(DF$Denial1) | DF$Denial2 < 1 &  
!is.na(DF$Denial2) | DF$Denial3 < 1 & !is.na(DF$Denial3), "0", "1")

Then to ensure a value of NA if all values of the conditional variables are NA:

DF$Den <- ifelse(is.na(DF$Denial1) & is.na(DF$Denial2) & is.na(DF$Denial3), 
NA, DF$Den)
EcologyTom
  • 2,344
  • 2
  • 27
  • 38
user3594490
  • 1,949
  • 2
  • 20
  • 26
8

How about?

DF$Den<-ifelse (is.na(DF$Denial1) | is.na(DF$Denial2) | is.na(DF$Denial3), "0", "1")
Old_Mortality
  • 519
  • 1
  • 4
  • 14
  • I'll try to clarify: I don't want a "0" if the value for a conditional variable is missing. I want a "0" in "Den" if any of the conditional variables has a "0". I only want a "1" in "Den" if every conditional variable that is not missing has a value of "1". Does that help? – user3594490 Apr 01 '16 at 18:07
  • and what do you want if one is missing? – Old_Mortality Apr 01 '16 at 18:10
  • If all 3 conditional variables are missing values, only then would I want "Den" to be missing. But I want the value of "Den" to be based on the conditional variables with values that aren't missing (i.e. "0" or "1". Your example above gives me a "0" when that condition should produce a "1" because the only conditional variable with a value ("Denial2") has a value of "1". – user3594490 Apr 01 '16 at 18:17
  • and it has to be in 1 statement? – Old_Mortality Apr 01 '16 at 18:43
  • No, I think I see what you're getting at, I can create the variable then use another conditional statement to to change it's value based on whether or not all three conditional variables are missing. – user3594490 Apr 01 '16 at 18:52
  • Something along those lines, yes. – Old_Mortality Apr 01 '16 at 18:58
4

There is a simpler solution to this. What you describe is the natural behavior of the & operator and can thus be done primitively:

> c(1,1,NA) & c(1,0,NA) & c(1,NA,NA)
[1]  TRUE FALSE    NA

If all are 1, then 1 is returned. If any are 0, then 0. If all are NA, then NA.

In your case, the code would be:

DF$Den<-DF$Denial1 & DF$Denial2 & DF$Denial3

In order for this to work, you will need to stop working in character and use numeric or logical types.

Nick Cox
  • 35,529
  • 6
  • 31
  • 47
Craig
  • 4,492
  • 2
  • 19
  • 22
4

Very simple use of any

df <- <your structure>

df$Den <- apply(df,1,function(i) {ifelse(any(is.na(i)) | any(i != 1), 0, 1)})
alexwhitworth
  • 4,839
  • 5
  • 32
  • 59
3

another solution using dplyr is:

df <- ## your data ##
df <- df %>%
        mutate(Den = ifelse(any(is.na(Den)) | any(Den != 1), 0, 1))
ahreje
  • 56
  • 1