Replace column values based on column name

Viewed 91

I have a data frame with several binary variables: x1, x2, ... x100. I want to replace the entry 1 in each column with the number in the name of the column, i.e.:

data$x2[data$x2 == 1] <- 2
data$x3[data$x3 == 1] <- 3
data$x4[data$x4 == 1] <- 4
data$x5[data$x5 == 1] <- 5
...

How can I achieve this in a loop?

4 Answers

Using col:

# example data
set.seed(1); d <- as.data.frame(matrix(sample(0:1, 12, replace = TRUE), nrow = 3))
names(d) <- paste0("x", seq(ncol(d)))

d  
#   x1 x2 x3 x4
# 1  0  0  0  1
# 2  1  1  0  0
# 3  0  0  1  0

ix <- d == 1
d[ ix ] <- col(d)[ ix ]

d
#   x1 x2 x3 x4
# 1  0  0  0  4
# 2  1  2  0  0
# 3  0  0  3  0

dplyr approach (using zx8754's data):

library(dplyr)

d %>% 
 mutate(across(starts_with('x'), ~ . * as.numeric(gsub('x', '', cur_column()))))
#>   x1 x2 x3 x4
#> 1  0  0  0  4
#> 2  1  2  0  0
#> 3  0  0  3  0

Created on 2021-05-26 by the reprex package (v2.0.0)

Here is a base R solution with a lapply loop.

data[-1] <- lapply(names(data)[-1], function(k){
  n <- as.integer(sub("[^[:digit:]]*", "", k))
  data[data[[k]] == 1, k] <- n
  data[[k]]
})
data

Test data.

set.seed(2021)
data <- replicate(6, rbinom(10, 1, 0.5))
data <- as.data.frame(data)
names(data) <- paste0("x", 1:6)

A solution based on a simple for loop is below (otherwise similar to the accepted answer using lapply):

for (i in 2:100) {
  k <- paste0('x', i)
  data[data[[k]] == 1, k] <- i
}
Related