【问题标题】:Store variable with multiple condition in for loop until condition is met in R在for循环中存储具有多个条件的变量,直到在R中满足条件
【发布时间】:2018-03-14 10:52:01
【问题描述】:

(我知道 for 循环不是 R 中的首选,但这是我能想到的最好的选择)

我正在尝试遍历向量并在满足条件后返回向量值。

一旦满足下一个条件,我想删除该变量。

到目前为止,我已经了解了以下内容:

df = c(1:10)

sig = function (df) {

  pos = integer(10)

  for (i in 1:10) {

    if (df[i] > 3 ) { # Once df[i] is bigger than 3 store the value of df[i]
      pos[i] = df[i]
    } 
    else if(df[i] < 7 ){ # Keep value of df[i] until next condition is met
      pos[i] = pos[i - 1]
    } 
    else{pos[i] = 0} # set the value back to 0
  }

  reclass(pos,df)
}

sig(df)

我收到以下错误Error in pos[i] &lt;- pos[i - 1] : replacement has length zero

答案应如下所示:

df  sig
1    0
2    0
3    0
4    4
5    4
6    4
7    0
8    0
9    0
10   0

有什么想法吗?

【问题讨论】:

    标签: r loops for-loop


    【解决方案1】:

    实现输出的另一种方式

    pos = integer(10)
    pos[df>3 & df<7]<-df[which.max(df>3 & df<7)]
    cbind(df,pos)
          df pos
     [1,]  1   0
     [2,]  2   0
     [3,]  3   0
     [4,]  4   4
     [5,]  5   4
     [6,]  6   4
     [7,]  7   0
     [8,]  8   0
     [9,]  9   0
    [10,] 10   0
    

    关于您的问题

    i 从 1 开始,在 for 循环中你有 pos[i-1],所以 pos[0] 但列表从 1 开始。

    试试这个:

    sig = function (df) {
    
      pos = integer(10)
    
      for (i in 1:10) {
    
        if (df[i] > 3 ) { # Once df[i] is bigger than 3 store the value of df[i]
          pos[i] = df[i]
        } 
        else if(df[i] < 7 ){ # Keep value of df[i] until next condition is met
          if(i>1) {
            pos[i] = pos[i - 1] 
          } else
    
          {
            pos[i]=0
          }
        } 
        else{pos[i] = 0} # set the value back to 0
      }
    
      return(cbind(df,pos))
    }
    

    return 指令添加

    你的输出:

    sig(df)
          df pos
     [1,]  1   0
     [2,]  2   0
     [3,]  3   0
     [4,]  4   4
     [5,]  5   5
     [6,]  6   6
     [7,]  7   7
     [8,]  8   8
     [9,]  9   9
    [10,] 10  10
    

    输出与一方面不同,因此您必须在 for 循环内的逻辑中查找其他错误。

    【讨论】:

      【解决方案2】:

      你可以用data.table来做,方法是这样的

      #Create the data.table
      dt <- data.table(c(1:10))
      #Create a keep column which is set to 1 for those which respect condition and 0 for the others
      dt[,keep:=ifelse(V1>3&V1<7,min(V1),0)][]
      #Then create sig column which contains only the value you want to keep 
      dt[,sig:=ifelse(keep==0,0,V1*keep)][]
      #And finally, you want to store only the first value which respect the condition, so if your data frame is order by number, you can take the min value by V1 column.
      dt[,sig:=min(sig),by=keep][]
      

      这是输出

      dt[,c(1,3)]
          V1 sig
       1:  1   0
       2:  2   0
       3:  3   0
       4:  4   4
       5:  5   4
       6:  6   4
       7:  7   0
       8:  8   0
       9:  9   0
      10: 10   0
      

      【讨论】:

        【解决方案3】:

        你也可以使用ifelse

        df <- c(1:10)
        ifelse(df > 3 & df < 7, df[which(df > 3)][1], 0)
        # [1] 0 0 0 4 4 4 0 0 0 0
        

        【讨论】:

          【解决方案4】:

          这是一个不使用for 循环的可能解决方案。相反,您可以使用rle

          a <- c(1:10)
          r <- rle(a > 3 & a < 7)
          r$values <- ifelse(r$values, a[head(cumsum(c(1, r$lengths)), -1)], 0)
          inverse.rle(r)
           [1] 0 0 0 4 4 4 0 0 0 0
          

          但请注意,这仅在向量已排序时才有效。

          另一个例子:

          > a <- c(4, 7, 9, 6, 5, 8, 10, 2, 3, 1)
          > r <- rle(a %% 2 == 0)
          > r$values <- ifelse(r$values, a[head(cumsum(c(1, r$lengths)), -1)], 0)
          > inverse.rle(r)
           [1] 4 0 0 6 0 8 8 8 0 0
          

          【讨论】:

            猜你喜欢
            • 2014-05-12
            • 2015-04-08
            • 2016-05-02
            • 1970-01-01
            • 1970-01-01
            • 2021-12-24
            • 1970-01-01
            • 1970-01-01
            • 2018-11-09
            相关资源
            最近更新 更多