Reputation: 87
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
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
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