Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use 'ifelse' and 'all' together?

Hope I am not duplicating another's question and perhaps a similar vein to my other question.

I am trying to

  1. Group the rows by ID
  2. Then: a) assign 'A' to those who only have received product 'A' b) assign 'P' to those who only have received product 'P' c) assign 'A and P' to those who have received both products d) assign NA to those who have not received either A or P

My data df

df <- read.table(text =
"      ID Product
 1     1 A      
 2     1 A      
 3     1 A      
 4     2 NA     
 5     2 NA     
 6     3 P      
 7     3 P      
 8     4 A      
 9     4 P      
10     5 A      
11     6 P      
12     7 NA    ")

My desired output:

      ID Product Group

 1     1 A       A    
 2     1 A       A    
 3     1 A       A    
 4     2 NA      NA   
 5     2 NA      NA   
 6     3 P       P    
 7     3 P       P    
 8     4 A       A_P  
 9     4 P       A_P  
10     5 A       A    
11     6 P       P    
12     7 NA      NA 

I've tried a few things, but the new column does not emerge:

df$Group <- df %>% 
  group_by(ID) %>%
  ifelse(all(df$Product==A), "A",
     ifelse(all(df$Product==P), "P",
            ifelse(all(df$Product==NA), "NA", "A_P") %>%
    ungroup()

I've also tried:

df$group <- df%>% 
  group_by(ID) %>%
  if(all(df$Product=="A") {
    df$group="A"
  } else if(all(df$Product=="P") {
      df$group="P"
  } else if(all(df$Product==NA) {
        df$group=NA
        }  else {df$group="A_P"}
    

But it keeps saying that my } is not supposed to be there which doesn't make sense to me?

My other question: Can you use all in ifelse statements for non-numerical vectors?

Thanks.

like image 821
Jobolo Avatar asked Dec 16 '25 12:12

Jobolo


2 Answers

Using ave, avoiding if-else.

transform(df, Group=ave(Product, ID, FUN=\(x) {
  u <- paste(sort(unique(x)), collapse='_');replace(u, u == '', NA)}))
#    ID Product Group
# 1   1       A     A
# 2   1       A     A
# 3   1       A     A
# 4   2    <NA>  <NA>
# 5   2    <NA>  <NA>
# 6   3       P     P
# 7   3       P     P
# 8   4       A   A_P
# 9   4       P   A_P
# 10  5       A     A
# 11  6       P     P
# 12  7    <NA>  <NA>

maybe consider toString to make it comma-separated

transform(df, Group=ave(Product, ID, FUN=\(x) {
  u <- toString(sort(unique(x)));replace(u, u == '', NA)}))
#    ID Product Group
# 1   1       A     A
# 2   1       A     A
# 3   1       A     A
# 4   2    <NA>  <NA>
# 5   2    <NA>  <NA>
# 6   3       P     P
# 7   3       P     P
# 8   4       A  A, P
# 9   4       P  A, P
# 10  5       A     A
# 11  6       P     P
# 12  7    <NA>  <NA>

Data:

df <- structure(list(ID = c(1L, 1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L, 5L, 
6L, 7L), Product = c("A", "A", "A", NA, NA, "P", "P", "A", "P", 
"A", "P", NA)), class = "data.frame", row.names = c("1", "2", 
"3", "4", "5", "6", "7", "8", "9", "10", "11", "12"))
like image 65
jay.sf Avatar answered Dec 19 '25 06:12

jay.sf


Here's my stab using base R and a few readable lines of code. :)

xy <- read.table(text =
                   "      ID Product
 1     1 A      
 2     1 A      
 3     1 A      
 4     2 NA     
 5     2 NA     
 6     3 P      
 7     3 P      
 8     4 A      
 9     4 P      
10     5 A      
11     6 P      
12     7 NA    ")

xygroup <- split(x = xy, f = xy$ID)

xy.withgroup <- lapply(X = xygroup, FUN = function(x) {
  unique.products <- unique(x$Product)
  if (all(is.na(unique.products))) {
    group <- NA
  } else {
    group <- paste(unique.products, collapse = "_")
  }
  
  x$Group <- group
  x
})

do.call(rbind, xy.withgroup)

    ID Product Group
1.1  1       A     A
1.2  1       A     A
1.3  1       A     A
2.4  2    <NA>  <NA>
2.5  2    <NA>  <NA>
3.6  3       P     P
3.7  3       P     P
4.8  4       A   A_P
4.9  4       P   A_P
5    5       A     A
6    6       P     P
7    7    <NA>  <NA>
like image 45
Roman Luštrik Avatar answered Dec 19 '25 06:12

Roman Luštrik