Loop to add new columns with ifelse

☆樱花仙子☆ 提交于 2020-01-03 09:01:47

问题


I would like to make my code more efficient, I have a survey where my data looks like:

survey <- data.frame(
                     x = c(1, 6, 2, 60, 75, 40, 27, 10),
                     y = c(100, 340, 670, 700, 450, 200, 136, 145)) 

#Two lists:
A <- c(3, 6, 7, 27, 40, 41)
t <- c(0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16)

What I did was create new columns, like this:

z <- ifelse(survey$x %in% A), 0, min(t))

for (i in t) {
  survey[paste0("T",i)] <-z
  survey[paste0("T",i)] <-ifelse (z > 0, i, z)
}

But with that code it takes a while, is there a better way to do it?


回答1:


As the OP mentioned about speed of execution, the data.table option would be faster

library(data.table)
i1 <- !survey$x %in% A

setDT(survey)[, paste0("T", t) := 0]
for(j in t) {
    set(survey2, i = which(i1), j = paste0("T", j), value = j) 
    }

Benchmarks

set.seed(24)
survey1 <- data.frame(x = sample(survey$x, 1e7, replace = TRUE),
       y = sample(survey$y, 1e7, replace = TRUE))

survey2 <- copy(survey1)

system.time({

survey1[paste0("T", t)] <- lapply(t, function(y) ifelse(survey1$x %in% A, 0, y))
})
# user  system elapsed 
#   8.20    2.75   11.03 

system.time({
i1 <- !survey2$x %in% A

setDT(survey2)[, paste0("T", t) := 0]
for(j in t) {
     set(survey2, i = which(i1), j = paste0("T", j), value = j) 
        }

})
# user  system elapsed 
#   0.97    0.31    1.28 



回答2:


You can use sapply for this:

#just make your new cols with sapply
newcols <- sapply(t, function(i) ifelse (z > 0, i, z))
#add the names you wanted
colnames(newcols) <- paste0("T", seq_along(t))
#merge to your original survey data set
cbind(survey, newcols)

#   x   y  T1   T2   T3   T4   T5   T6   T7
#1  1 100 0.1 0.11 0.12 0.13 0.14 0.15 0.16
#2  6 340 0.0 0.00 0.00 0.00 0.00 0.00 0.00
#3  2 670 0.1 0.11 0.12 0.13 0.14 0.15 0.16
#4 60 700 0.1 0.11 0.12 0.13 0.14 0.15 0.16
#5 75 450 0.1 0.11 0.12 0.13 0.14 0.15 0.16
#6 40 200 0.0 0.00 0.00 0.00 0.00 0.00 0.00
#7 27 136 0.0 0.00 0.00 0.00 0.00 0.00 0.00
#8 10 145 0.1 0.11 0.12 0.13 0.14 0.15 0.16



回答3:


It may be even faster to use matrix multiplication.

dat <- cbind(survey, matrix(!survey$x %in% A) %*% t)
   x   y   1    2    3    4    5    6    7
1  1 100 0.1 0.11 0.12 0.13 0.14 0.15 0.16
2  6 340 0.0 0.00 0.00 0.00 0.00 0.00 0.00
3  2 670 0.1 0.11 0.12 0.13 0.14 0.15 0.16
4 60 700 0.1 0.11 0.12 0.13 0.14 0.15 0.16
5 75 450 0.1 0.11 0.12 0.13 0.14 0.15 0.16
6 40 200 0.0 0.00 0.00 0.00 0.00 0.00 0.00
7 27 136 0.0 0.00 0.00 0.00 0.00 0.00 0.00
8 10 145 0.1 0.11 0.12 0.13 0.14 0.15 0.16

Here, matrix(!survey$x %in% A) constructs a nX1 matrix with TRUEs and FALSEs based on the whether the values of survey$x is present in A. This result is matrix multiplied (%*%) by t, which is treated as a 1Xn matrix. Then result is the desired output.

You can add the column names afterward if desired using the code in lyzander's answer.



来源:https://stackoverflow.com/questions/47507915/loop-to-add-new-columns-with-ifelse

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!