功能比r中的ifelse()更快

时间:2018-04-25 07:06:44

标签: r if-statement

我有3列举报,分数,舞台

标志将具有值1或0,分数将是高于0的任何值。我们需要计算阶段值。

所以我们的数据(stagedata)将如下所示:

              Flag Score Stage
               1    35
               1    0
               0    12
               ....

如果标志== 1且得分> = 30,我们将阶段计算为2,

并且如果Flag == 0或Flag == 1并且得分< 30,阶段= 1。

任何其他案例阶段将被计算为0(即,由于输入中的某些错误或缺少得分或标志)。

        stagedata$Stage <- ifelse(stagedata$Flag==1,ifelse((stagedata$Score>=30),2,1),ifelse(stagedata$Flag==0,1,0))
        stagedata$Stage[is.na(stagedata$Stage)] <-0

使用像apply这样的任何其他功能有更有效的方法吗?我们正在处理的数据大约是10个数字

2 个答案:

答案 0 :(得分:2)

我们可以通过一些算术运算将逻辑向量转换为整数

v1 <- with(stagedata, 2 *(Flag == 1 & score >= 30) + (Flag %in% 0:1 & score <30))
v1
#[1] 2 1 1 2 1 0

如果有NA值,则将其替换为0

v1[is.na(v1)] <- 0

数据

stagedata <- data.frame(Flag = c(1, 1, 0, 1, 0, 2), score = c(35, 0, 12, 31, 27, 31))

答案 1 :(得分:2)

原始答案和固定答案是不同的1.07x - 而不是1.4x - 不是有意义的差异

N <- 10000
set.seed(1)
df <- data.frame(Flag = sample(0:1, N, replace=T), Score = sample(c(12, 35), N, replace=T))
  # Flag Score
# 1    0    12
# 2    0    35
# 3    1    35
# 4    1    12
# 5    0    12
# 6    1    12

ifelse_approach <- function() {
  df$Stage <- ifelse(df$Flag==1,ifelse((df$Score>=30),2,1),ifelse(df$Flag==0,1,0))
}

lgl_approach <- function() {
  df$Stage <- with(df, 2 *(Flag == 1 & Score >= 30) + (Flag %in% 0:1 & Score <30))
}

lgl_fix_approach <- function() {
  df$Stage <- with(df, 2 *(Flag == 1 & Score >= 30) + (Flag == 0 | Score < 30))
}

identical(ifelse_approach(), lgl_approach())
# FALSE
identical(ifelse_approach(), lgl_fix_approach())
# TRUE

library(microbenchmark)
microbenchmark(ifelse_approach(), lgl_approach(), lgl_fix_approach(), unit="relative", times=10L)

# Unit: relative
               # expr      min       lq     mean   median       uq       max neval
  # ifelse_approach() 5.949921 6.048253 5.714637 6.737770 7.186373 3.0478402    10
     # lgl_approach() 1.120431 1.111262 1.059140 1.274285 1.376115 0.5364108    10
 # lgl_fix_approach() 1.000000 1.000000 1.000000 1.000000 1.000000 1.0000000    10