r label variable combination

Viewed 120

I have a dataset with three variables. Each variable can take two values "Yes" or "No". So 2^3=8 different combinations of these three variables.

 C1   C2   C3
 Yes  No   No
 No   Yes  No
 No   Yes  No
 No   Yes  No
 Yes  Yes  Yes 
 No   No   Yes
 No   No   No
 Yes  Yes  No
 Yes  Yes  No
 No   Yes  Yes
 Yes  No   Yes
 Yes  No   Yes
 Yes  Yes  Yes

How do I create a fourth column that indicates the column C1, C2, C3 combination ? The expected output would be

 C1   C2   C3   I
 Yes  No   No   1
 No   Yes  No   2
 No   Yes  No   2
 No   Yes  No   2
 Yes  Yes  Yes  8
 No   No   Yes  3 
 No   No   No   4 
 Yes  Yes  No   5
 Yes  Yes  No   5
 No   Yes  Yes  6
 Yes  No   Yes  7 
 Yes  No   Yes  7
 Yes  Yes  Yes  8
2 Answers

An option using data.table:

DT[order(C1, C2, C3), Idx := rleidv(.SD)]   

Or using a lookup join as mentioned by Nadia so that you can control the indexing:

x <- c("No", "Yes")
DT[CJ(C1=x, C2=x, C3=x)[, Idx := .I], on=.NATURAL, Idx := Idx]

output:

     C1  C2  C3 Idx
 1: Yes  No  No   5
 2:  No Yes  No   3
 3:  No Yes  No   3
 4:  No Yes  No   3
 5: Yes Yes Yes   8
 6:  No  No Yes   2
 7:  No  No  No   1
 8: Yes Yes  No   7
 9: Yes Yes  No   7
10:  No Yes Yes   4
11: Yes  No Yes   6
12: Yes  No Yes   6
13: Yes Yes Yes   8

data:

library(data.table)
DT <- fread("C1   C2   C3
Yes  No   No
No   Yes  No
No   Yes  No
No   Yes  No
Yes  Yes  Yes 
No   No   Yes
No   No   No
Yes  Yes  No
Yes  Yes  No
No   Yes  Yes
Yes  No   Yes
Yes  No   Yes
Yes  Yes  Yes")

As @Nadia points out in the comments, there is a natural method for obtaining the order using powers of 2. If we had other options in addition to "Yes" and "No" (e.g. "Maybe") we would use powers of 3 (or 4, 5, etc.). In base R we have:

df$Index <- apply(df, 1, function(x) sum(2^(which(x == "Yes") - 1L)) + 1L)

This gives:

df
    C1  C2  C3 Index
1  Yes  No  No     2
2   No Yes  No     3
3   No Yes  No     3
4   No Yes  No     3
5  Yes Yes Yes     8
6   No  No Yes     5
7   No  No  No     1
8  Yes Yes  No     4
9  Yes Yes  No     4
10  No Yes Yes     7
11 Yes  No Yes     6
12 Yes  No Yes     6
13 Yes Yes Yes     8

I doubt this is faster than the data.table version, however the intent of the answer is purely pedagogical.

Here is the input for reference:

df <- read.table(text = "C1   C2   C3
                        Yes  No   No
                        No   Yes  No
                        No   Yes  No
                        No   Yes  No
                        Yes  Yes  Yes 
                        No   No   Yes
                        No   No   No
                        Yes  Yes  No
                        Yes  Yes  No
                        No   Yes  Yes
                        Yes  No   Yes
                        Yes  No   Yes
                        Yes  Yes  Yes",
                header = TRUE)
Related