如何使用for循环基于以前的列更新每个列

时间:2018-02-02 21:17:45

标签: r for-loop if-statement

我的数据包含一个id变量,然后是多个访问变量,用于跟踪人们随时间的分数。我正在尝试将分数向前推进,将任何后续零点更新为该分数。如果有NA,我想留下它(代表没有访问),如果一个人稍后获得新分数,我希望新分数继续发展。

我已经包含了一个可重复的小例子,但我的实际数据非常大,因此不能手动更新。我目前的尝试是使用for循环遍历每个人(行)的访问列。但是我收到了这个警告:

if((!is.na(first)& first!= 0)&(!is.na(second)& second ==)出错   参数长度为零 另外:警告信息: 在is.na(第二个)中:is.na()应用于类型为' NULL'

的非(列表或向量)

看起来是因为在环境(Rstuio)中,第一个值为NA_real_,第二个值为NULL(空)。

如何正确定义这些? 我没有太多的for循环经验,欢迎大家提出建议!

id <- c(101, 102, 103, 104)
visit.1 <- c(0, 21, 0, 21)
visit.2 <- c(0, 0, 50, 0)
visit.3 <- c(0, 0, 0, 44)
visit.4 <- c(NA, NA, 0, 0)
dat <- data.frame(id, visit.1, visit.2, visit.3, visit.4)


for(i in 1:nrow(dat)){
  for(j in 2:ncol(dat)){

    first <- dat[i, j]
    second <- dat[i,(j+1)]

    if((!is.na(first) & first != 0) & (!is.na(second) & second == 0)){
      second <- first
      } else {
        second <- second
      }
   }
  }

原始数据集:

id visit.1 visit.2 visit.3 visit.4
1 101       0       0       0      NA
2 102      21       0       0      NA
3 103       0      50       0       0
4 104      21       0      44       0

期望的最终结果:

id visit.1 visit.2 visit.3 visit.4
1 101       0       0       0      NA
2 102      21      21      21      NA
3 103       0      50      50      50
4 104      21      21      44      44

4 个答案:

答案 0 :(得分:3)

一种非常简单的方法是消除内部循环并对内部替换循环进行矢量化。这不是最好的解决方案,但更接近您更熟悉的内容:

id <- c(101, 102, 103, 104)
visit.1 <- c(0, 21, 0, 21)
visit.2 <- c(0, 0, 50, 0)
visit.3 <- c(0, 0, 0, 44)
visit.4 <- c(NA, NA, 0, 0)
dat <- data.frame(id, visit.1, visit.2, visit.3, visit.4)

for (index in 3:5){
  dat[[index]]<-ifelse(dat[[index]]==0, dat[[index-1]], dat[[index]])
}

我正在使用for循环从列移动到列。然后ifelse正在查看整个列。对于== 0的行,如果不使用当前值,则使用左侧的值。

答案 1 :(得分:2)

Dave2e用更少的代码行回答了你的问题,但我稍微修改了你的尝试,以便你可以看到你做错了什么:

from flask import Flask

app = Flask(__name__)
app.config['DEBUG'] = False

@app.route('/test')
def test():
    return 'hello world'

首先使用for(i in 1:nrow(newdat)){ for(j in 3:ncol(newdat)) { first <- newdat[i, j-1] second <- newdat[i, j] if(!is.na(first) & !is.na(second) & second == 0){ newdat[i,j] <- first } } } 您在dat[i,(j+1)]中计算得太多,所以我使用了for(j in 2:ncol(dat)){ ... }并设置了3:ncol(dat)。 其次first <- newdat[i, j-1]无法正常工作,您需要直接处理数据框。

答案 2 :(得分:1)

zoo::na.locf可以在这里使用

library(zoo)
data <- tail(t(dat), -1)

        # [,1] [,2] [,3] [,4]
# visit.1    0   21    0   21
# visit.2    0    0   50    0
# visit.3    0    0    0   44
# visit.4   NA   NA    0    0

placeholder_value <- function(mat) {
    head(setdiff(seq(0, max(c(mat), na.rm=TRUE), 1), unique(c(mat))), 1)
}
val <- placeholder_value(data)

由于na.locf会搜索要归待的NA值,因此NA值会在运行na.locf之前更改为占位符值(并且0更改为{ {1}}),然后将这些值转换回原始值。

NA

答案 3 :(得分:1)

另一个基础R方法将是我们ave

cbind(dat[1],t(apply(dat[-1],1,function(x)ave(x,cumsum(x),FUN=sum))))
   id visit.1 visit.2 visit.3 visit.4
1 101       0       0       0      NA
2 102      21      21      21      NA
3 103       0      50      50      50
4 104      21      21      44      44

data.table格式。没有涉及循环:

library(data.table)
A=setDT(melt(dat,1))[,.(variable,ave(value,cumsum(value),FUN=sum)),by=id]
dcast(A,id~variable,value.var = "V2")
   id visit.1 visit.2 visit.3 visit.4
1 101       0       0       0      NA
2 102      21      21      21      NA
3 103       0      50      50      50
4 104      21      21      44      44