比'for'循环使用R更有效的方法

Dan*_*wer 7 for-loop r survey apply

我是R的相对新人,所以如果对此有明显的答案,我很抱歉.我已经查看了其他问题,我认为"应用"是答案,但在这种情况下我无法弄清楚如何使用它.

我有一个纵向调查,每年邀请参与者.有些年份他们没有参加,有时他们会死.从调查开始以来,我需要确定哪些参与者参与了一致的"连胜"(即如果他们停止,他们就会停下来).

我用'for'循环完成了这个,在下面的例子中工作正常.但是我有很多年和很多参与者,而且循环非常慢.我可以用更快的方法吗?

在示例中,TRUE表示他们参加了那一年.循环创造了两个向量 - 他们参与的最后一年的'finalyear',并且'streak'表示他们是否在最后一年(即案例1,3和5)完成了所有年份.

dat <- data.frame(ids = 1:5, "1999" = c(T, T, T, F, T), "2000" = c(T, F, T, F, T), "2001" = c(T, T, T, T, T), "2002" = c(F, T, T, T, T), "2003" = c(F, T, T, T, F))
finalyear <- NULL
streak <- NULL
for (i in 1:nrow(dat)) {
    x <- as.numeric(dat[i,2:6])
    y <- max(grep(1, x))
    finalyear[i] <- y
    streak[i] <- sum(x) == y
}
dat$finalyear <- finalyear
dat$streak <- streak
Run Code Online (Sandbox Code Playgroud)

谢谢!

akr*_*run 5

我们可以使用max.colandrowSums作为一种vectorized方法。

dat$finalyear <- max.col(dat[-1], 'last')
Run Code Online (Sandbox Code Playgroud)

如果存在没有TRUE值的行,我们可以通过乘以 的双重否定来确保该行返回 0 rowSums。该FALSE行将被强制为 0,并与 0 相乘返回 0。

dat$finalyear <- max.col(dat[-1], 'last')*!!rowSums(dat[-1])
Run Code Online (Sandbox Code Playgroud)

rowSums然后,我们通过比较列 2:6 与“finalyear”的列来创建“streak”列

dat$streak <-  rowSums(dat[,2:6])==dat$finalyear
dat
#   ids X1999 X2000 X2001 X2002 X2003 finalyear streak
#1   1  TRUE  TRUE  TRUE FALSE FALSE         3   TRUE
#2   2  TRUE FALSE  TRUE  TRUE  TRUE         5  FALSE
#3   3  TRUE  TRUE  TRUE  TRUE  TRUE         5   TRUE
#4   4 FALSE FALSE  TRUE  TRUE  TRUE         5  FALSE
#5   5  TRUE  TRUE  TRUE  TRUE FALSE         4   TRUE
Run Code Online (Sandbox Code Playgroud)

或者 @ColonelBeauvel 建议的一行代码(它可以适合一行,但决定通过 2 行使其明显)

library(dplyr)
mutate(dat, finalyear=max.col(dat[-1], 'last'), 
            streak=rowSums(dat[-1])==finalyear)
Run Code Online (Sandbox Code Playgroud)

  • 一个带有 `mutate(dat, Finalyear=max.col(dat[-1], 'last'), streak=rowSums(dat[-1])==finalyear)` 的班轮 (2认同)