【问题标题】:Loop to add new columns with ifelse循环以使用 ifelse 添加新列
【发布时间】:2018-05-10 12:19:34
【问题描述】:

我想让我的代码更高效,我有一个调查,我的数据如下所示:

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)

我所做的是创建新列,如下所示:

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)
}

但是使用该代码需要一段时间,有没有更好的方法来做到这一点?

【问题讨论】:

  • 你可以做survey[paste0("T", t)] &lt;- lapply(t, function(y) ifelse(survey$x %in% A, 0, y))
  • 您也可以查看data.table,这可能更快,即setDT(survey)[, paste0("T", t) := 0]; for(j in t) { set(survey, i = which(!survey$x %in% A), j = paste0("T", j), value = j) }

标签: r loops if-statement dataframe survey


【解决方案1】:

正如 OP 提到的执行速度,data.table 选项会更快

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) 
    }

基准测试

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 

【讨论】:

  • 为什么不需要逗号来表示您正在输入列?例如。为什么不是:survey1[, paste0("T", t)] 而不是 survey1[paste0("T", t)]
  • @user63230 setDT(survey)[, paste0("T", t) := 0] 逗号是指定i 即在data.table中是i, j, by格式
  • 对不起,我不是在谈论 data.table 解决方案。我的意思是survey1[paste0("T", t)] &lt;- lapply(t, function(y) ifelse(survey1$x %in% A, 0, y))。您通常必须引用您正在使用的列 [, ]?
【解决方案2】:

您可以为此使用sapply

#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】:

    使用矩阵乘法可能会更快。

    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
    

    这里,matrix(!survey$x %in% A) 根据survey$x 的值是否存在于A 中构造一个nX1 矩阵,该矩阵具有TRUE 和FALSE。这个结果是矩阵乘以(%*%)乘以t,被视为1Xn矩阵。那么结果就是想要的输出。

    如果需要,您可以在之后使用 lyzander 答案中的代码添加列名。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-16
      • 1970-01-01
      • 1970-01-01
      • 2020-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多