Fritzbrause
Fritzbrause

Reputation: 87

Replace value in column with dplyr based on given index

I am trying to replace a value (e.g. always 1) in a specific column of a dataframe. The column index for the replacement is given in column j .

It works with a for loop:

data <- data.frame(v1 = rep(0, 10),
               v2 = rep(0, 10),
               j = sample(1:2, 10, replace = TRUE))

for (i in 1: nrow(data)){
  data[i, (data$j[i])] <- 1
}

I am looking for the dplyr way of handling this situation.

Upvotes: 2

Views: 3122

Answers (2)

River
River

Reputation: 1514

Here is a dplyr version, using bind_rows. First let's set up data:

set.seed(2)
data <- data.frame(v1 = rep(0, 10),
                   v2 = rep(0, 10),
                   j = sample(1:2, 10, replace = TRUE))

Then we load dplyr and use do to act on each row. Here we use do to return one data frame per row, and bind_rows to merge them all together. The data in each row can be accessed using the . variable.

library(dplyr)

data %>%
    do(data.frame(v1 = ifelse(.$j == 1, 1, .$v1),
                  v2 = ifelse(.$j == 2, 1, .$v2),
                  j = .$j)) %>% 
    bind_rows() 


#   v1 v2 j
#1   1  0 1
#2   0  1 2
#3   0  1 2
#4   1  0 1
#5   0  1 2
#6   0  1 2
#7   1  0 1
#8   0  1 2
#9   1  0 1
#10  0  1 2

An even shorter solution, suggested by @Akrun, is:

data %>% mutate(v1 = +(j==1), v2 = +(j==2))

Upvotes: 4

akrun
akrun

Reputation: 887911

This can be easily done with row/column indexing and it should be faster

data[cbind(1:nrow(data), data$j)] <- 1
data
#   v1 v2 j
#1   0  1 2
#2   1  0 1
#3   0  1 2
#4   0  1 2
#5   0  1 2
#6   0  1 2
#7   0  1 2
#8   1  0 1
#9   1  0 1
#10  0  1 2

Or another way is

library(tidyr)
library(dplyr)
tibble::rownames_to_column(data, var = "rn") %>%
           gather(Var, Val, v1:v2) %>% 
           mutate(Val= +(sub("\\D+", "", Var)==j)) %>% 
           spread(Var, Val) %>% 
           arrange(as.numeric(rn)) %>%
           select_(.dots=names(data))
#   v1 v2 j
#1   0  1 2
#2   1  0 1
#3   0  1 2
#4   0  1 2
#5   0  1 2
#6   0  1 2
#7   0  1 2
#8   1  0 1
#9   1  0 1
#10  0  1 2

Upvotes: 3

Related Questions