dummy variables to single categorical variable (factor) in R
Asked Answered
A

2

9

I have a set of variables coded as binomial.

   Pre VALUE_1 VALUE_2 VALUE_3 VALUE_4 VALUE_5 VALUE_6 VALUE_7 VALUE_8 
1   1       0       0       0       0       0       1       0       0       
2   1       0       0       0       0       1       0       0       0       
3   1       0       0       0       0       1       0       0       0       
4   1       0       0       0       0       1       0       0       0           

I would like to merge the variables (VALUE_1, VALUE_2...VALUE_8) into one single ordered factor, while conserving the column (Pre) as is, duch that the data would look like this:

  Pre VALUE
1  1  VALUE_6
2  1  VALUE_5
3  1  VALUE_5

Or even better:

  Pre VALUE
1  1  6
2  1  5
3  1  5

I am aware that this exists: Recoding dummy variable to ordered factor

But when I try the code used in that post, I receive the following error:

PA2$Factor = factor(apply(PA2, 1, function(x) which(x == 1)), labels = colnames(PA2)) 

Error in sort.list(y) : 'x' must be atomic for 'sort.list'
Have you called 'sort' on a list?

Any help would be appreciated

Annetteannex answered 25/4, 2015 at 21:34 Comment(0)
N
10

A quick solution would be something like

Res <- cbind(df[1], VALUE = factor(max.col(df[-1]), ordered = TRUE))
Res
#   Pre VALUE
# 1   1     6
# 2   1     5
# 3   1     5
# 4   1     5

str(Res)
# 'data.frame':  4 obs. of  2 variables:
# $ Pre  : int  1 1 1 1
# $ VALUE: Ord.factor w/ 2 levels "5"<"6": 2 1 1 1

OR if you want the actual names of the columns (as Pointed by @BondedDust), you can use the same methodology to extract them

factor(names(df)[1 + max.col(df[-1])], ordered = TRUE)
# [1] VALUE_6 VALUE_5 VALUE_5 VALUE_5
# Levels: VALUE_5 < VALUE_6

OR you can use your own which strategy in the following way (btw, which is vectorized so no need in using apply with a margin of 1 on it)

cbind(df[1], VALUE = factor(which(df[-1] == 1, arr.ind = TRUE)[, 2], ordered = TRUE))

OR you can do matrix multiplication (contributed by @akrun)

cbind(df[1], VALUE = factor(as.matrix(df[-1]) %*% seq_along(df[-1]), ordered = TRUE))
Now answered 25/4, 2015 at 21:37 Comment(0)
L
0

One idea is you can convert 0s to NAs, then pivot the data dropping NA rows, then drop the values column of 1s. See Convert various dummy/logical variables into a single categorical variable/factor from their name in R

df <- data.frame(id = c(1, 2, 3), a = c(1, 0, 0), b = c(0, 1, 1))
df %>% mutate_all(~na_if(.,0)) %>% pivot_longer(a:b, values_drop_na=TRUE) %>% select(-value)

Output

# A tibble: 3 × 2
     id name 
  <dbl> <chr>
1     1 a    
2     2 b    
3     3 b    
Lasting answered 12/10, 2023 at 16:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.