【问题标题】:Filling data frame with previous row value用前一行值填充数据框
【发布时间】:2013-12-23 08:10:42
【问题描述】:

我有一个包含 2 列的数据框。

column1 有随机数 column2 是一个占位列,用于存放我希望 column3 看起来的样子

  random    temp
0.502423373 1
0.687594055 0
0.741883739 0
0.445364032 0
0.50626137  0.5
0.516364981 0
...

我想填充 column3,因此它采用最后一个非零数字(在本例中为 1 或 .5)并用该值连续填充以下行,直到它遇到具有不同数字的行。然后它对整个列重复该过程。

random     temp state
0.502423373 1   1
0.687594055 0   1
0.741883739 0   1
0.445364032 0   1
0.50626137  0.5 0.5
0.516364981 0   0.5
0.807804708 0   0.5
0.247948445 0   0.5
0.46573337  0   0.5
0.103705154 0   0.5
0.079625868 1   1
0.938928944 0   1
0.677713019 0   1
0.112231619 0   1
0.165907178 0   1
0.836195267 0   1
0.387712998 1   1
0.147737077 0   1
0.439281543 0.5 0.5
0.089013503 0   0.5
0.84174743  0   0.5
0.931738707 0   0.5
0.807955172 1   1

感谢大家的帮助

【问题讨论】:

    标签: r dataframe calculated-columns


    【解决方案1】:

    也许您可以在将“0”值设置为NA 后使用“zoo”包中的na.locf。假设您的 data.frame 被称为“mydf”:

    mydf$state <- mydf$temp
    mydf$state[mydf$state == 0] <- NA
    
    library(zoo)
    mydf$state <- na.locf(mydf$state)
    #      random temp state
    # 1 0.5024234  1.0   1.0
    # 2 0.6875941  0.0   1.0
    # 3 0.7418837  0.0   1.0
    # 4 0.4453640  0.0   1.0
    # 5 0.5062614  0.5   0.5
    # 6 0.5163650  0.0   0.5
    

    如果在“temp”列中的原始data.frame 中有NA 值,并且您希望在新生成的“state”列中也将它们保留为NA,这很容易处理。只需再添加一行以重新引入 NA 值:

    mydf$state[is.na(mydf$temp)] <- NA
    

    【讨论】:

    • 如果数据中已经有 NA,我认为这会很糟糕。但如果它有效,那也很好。
    • @NealFultz,那条评论值得否决?很容易解决您对评论的担忧。 (我假设您希望生成的“状态”变量中的值是NA,如果它是“temp”变量中的NA。请注意,我没有触摸“temp”变量,所以我仍然可以轻松访问这些信息。)
    • 如果您的 NA 靠近 0?
    • @NealFultz,???我应该怎么知道。这不是我的数据,问题中未指定这些条件。我仍然猜测应该将零旁边的NA 替换为最后一个已知值,并且对于当前数据集,我认为这不会是一个问题。或者你想在遇到NA 时继续用NA 填充数据?请随时分享您认为的情况以及您建议如何处理它。我没有看到您目前的解决方案处理 NA 值,所以我渴望学习。
    • 澄清一下,没有 NA,所以这个解决方案成功了!
    【解决方案2】:

    受@Ananda Mahto 解决方案的启发,这是对na.locf 内部代码的改编,直接与0 一起使用,而不是NAs。那么您就不需要zoo 包,也不需要进行将值更改为NA 的预处理。基准测试表明,这比原始版本快了大约 10 倍。

    locf.0 <- function(x) {
      L <- x!=0
      idx <- c(0, which(L))[cumsum(L) + 1]
      return(x[idx])
    } 
    mydf$state <- locf.0(mydf$temp)
    

    【讨论】:

    • 巧妙地修改na.locf。 +1
    【解决方案3】:

    这是Reduce 函数的一种有趣方式。

    temp = c(1,0,0,0,.5,0,0,0,0,0,1,0,0,0,0,0,1,0,0.5,0,0,0,1)
    fill_zero = function(x,y) if(y==0) x else y
    state = Reduce(fill_zero, temp, accumulate=TRUE)
    

    如果担心速度,可以试试 Rcpp。

    library(Rcpp)
    cppFunction('
      NumericVector fill_zeros( NumericVector x ) {
        for( int i=1; i<x.size(); i++ )
         if( x[i]==0 ) x[i] = x[i-1];
        return x;
      }
    ')
    state = fill_zeros(temp)
    

    【讨论】:

      【解决方案4】:

      此外,除非我忽略了某些东西,否则这似乎可行:

      DF$state2 <- ave(DF$temp, cumsum(DF$temp), FUN = function(x) x[x != 0])
      DF
      #       random temp state state2
      #1  0.50242337  1.0   1.0    1.0
      #2  0.68759406  0.0   1.0    1.0
      #3  0.74188374  0.0   1.0    1.0
      #4  0.44536403  0.0   1.0    1.0
      #5  0.50626137  0.5   0.5    0.5
      #6  0.51636498  0.0   0.5    0.5
      #7  0.80780471  0.0   0.5    0.5
      #8  0.24794844  0.0   0.5    0.5
      #9  0.46573337  0.0   0.5    0.5
      #10 0.10370515  0.0   0.5    0.5
      #11 0.07962587  1.0   1.0    1.0
      #12 0.93892894  0.0   1.0    1.0
      #13 0.67771302  0.0   1.0    1.0
      #14 0.11223162  0.0   1.0    1.0
      #15 0.16590718  0.0   1.0    1.0
      #16 0.83619527  0.0   1.0    1.0
      #17 0.38771300  1.0   1.0    1.0
      #18 0.14773708  0.0   1.0    1.0
      #19 0.43928154  0.5   0.5    0.5
      #20 0.08901350  0.0   0.5    0.5
      #21 0.84174743  0.0   0.5    0.5
      #22 0.93173871  0.0   0.5    0.5
      #23 0.80795517  1.0   1.0    1.0
      

      【讨论】:

      • 我认为ave(DF$temp, cumsum(DF$temp), FUN = sum) 应该也可以。
      • @Kevin:是的,你是对的!在这种情况下,summing 这些值也有效。而且,也许它也更快,因为它避免在索引之前转向逻辑?虽然,我仍然可能更喜欢x[x != 0],因为它准确地声明了averaging 函数是什么。
      【解决方案5】:

      以下几行的循环应该可以为您解决问题 -

      for(i in seq(nrow(df)))
      {
        if (df[i,"v1"] == 0) df[i,"v1"] <- df[i-1,"v1"]
      }
      

      输出 -

      > df
         v1 somedata
      1   1       33
      2   2       24
      3   1       36
      4   0       49
      5   2       89
      6   2       48
      7   0        4
      8   1       98
      9   1       60
      10  2       76
      > 
      > for(i in seq(nrow(df)))
      + {
      +   if (df[i,"v1"] == 0) df[i,"v1"] <- df[i-1,"v1"]
      + }
      > df
         v1 somedata
      1   1       33
      2   2       24
      3   1       36
      4   1       49
      5   2       89
      6   2       48
      7   2        4
      8   1       98
      9   1       60
      10  2       76
      

      【讨论】:

        【解决方案6】:

        我建议使用运行长度编码函数,这是处理数据集中的牛排的一种自然方式。使用@Kevin 的示例向量:

        temp = c(1,0,0,0,.5,0,0,0,0,0,1,0,0,0,0,0,1,0,0.5,0,0,0,1)
        y <- rle(temp)
        #str(y)
        #List of 2
        # $ lengths: int [1:11] 1 3 1 5 1 5 1 1 1 3 ...
        # $ values : num [1:11] 1 0 0.5 0 1 0 1 0 0.5 0 ...
        # - attr(*, "class")= chr "rle"
        
        
        for( i in seq(y$values)[-1] ) {
           if(y$values[i] == 0) {
              y$lengths[i-1] = y$lengths[i] + y$lengths[i-1]
              y$lengths[i] = 0
           }
        }
        
        #str(y)
        #List of 2
        # $ lengths: num [1:11] 4 0 6 0 6 0 2 0 4 0 ...
        # $ values : num [1:11] 1 0 0.5 0 1 0 1 0 0.5 0 ...
        # - attr(*, "class")= chr "rle"
        
        inverse.rle(y)
        #  [1] 1.0 1.0 1.0 1.0 0.5 0.5 0.5 0.5 0.5 0.5 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.5
        # [20] 0.5 0.5 0.5 1.0
        

        【讨论】:

        • 您需要一些 A-1 数据酱来搭配这些牛排吗? :-0
        【解决方案7】:

        只需使用带有全局变量的循环,

        这里使用的全局变量是mr是一个有两列AB的数据框。

        r$B = c(1,NA, NA, NA, 3, NA,6)
        
        
        m=1
        
        for( i in 1:nrow(r) ){
        
          if(is.na(r$B[i])==FALSE ){
        
            m <<- i # please note the assign sign ,  " <<- "
            next()
        
          } else {
        
            r$B[i] = r$B[m]
        
          }
        
        }
        

        执行后: r$B = 1 1 1 1 3 3 6

        【讨论】:

        • 首先,这是一种非常糟糕且不像 R 的方式来实现 OP 所追求的目标。有很多 much 更好(和矢量化)的替代方案,请参阅这篇文章的其他答案。其次,您提供的代码实际上是不可重现的。 r 没有在任何地方定义,您提到 R 作为 data.frame 但 R 区分大小写。在这种情况下使用&lt;&lt;- 正是 使用&lt;&lt;- 的示例之一:The Evil and Wrong use is to modify variables in the global environment
        • [继续] 最后,nextcontrol flow statementnext 不返回值,它应该是next 而不是next()。我认为这个答案对这篇文章贡献不大(如果有的话),因此应该删除,因为它促进了糟糕的 R 编码实践。
        猜你喜欢
        • 1970-01-01
        • 2015-01-24
        • 2019-10-28
        • 2019-05-02
        • 1970-01-01
        • 1970-01-01
        • 2020-11-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多