【问题标题】:Last Observation Carried Forward In a data frame? [duplicate]在数据框中进行的最后一次观察? [复制]
【发布时间】:2011-02-16 02:18:16
【问题描述】:

我希望为我正在处理的数据集实施“最后一次观察结转”,该数据集的末尾有缺失值。

这是一个简单的代码(后面的问题):

LOCF <- function(x)
{
    # Last Observation Carried Forward (for a left to right series)
    LOCF <- max(which(!is.na(x))) # the location of the Last Observation to Carry Forward
    x[LOCF:length(x)] <- x[LOCF]
    return(x)
}


# example:
LOCF(c(1,2,3,4,NA,NA))
LOCF(c(1,NA,3,4,NA,NA))

现在这对于简单的向量非常有用。但是如果我在哪里尝试在数据框上使用它:

a <- data.frame(rep("a",4), 1:4,1:4, c(1,NA,NA,NA))
a
t(apply(a, 1, LOCF)) # will make a mess

它将我的数据框变成字符矩阵。

你能想出一种在 data.frame 上进行 LOCF 而不将其转换为矩阵的方法吗? (我可以使用循环等来纠正混乱,但希望有一个更优雅的解决方案)

【问题讨论】:

    标签: r matrix apply dataframe


    【解决方案1】:

    这已经存在:

    library(zoo)
    na.locf(data.frame(rep("a",4), 1:4,1:4, c(1,NA,NA,NA)))
    

    【讨论】:

    • +1 和 rseek.org 当然会立即将其作为第一个结果。
    • 我不重新寻找它的出价 - 谢谢Shane。但我担心它不起作用。 (它填充第 3 列,而不是每一行)
    • 如果您在 stackoverflow.com 中搜索 [r] locf,您也可以找到这个。
    • 嗨 Shane,我也无法在该搜索中找到解决方案(虽然这个帖子很好:stackoverflow.com/questions/1782704/…
    • 如果缺少第一个值,那么您可以判断如何处理它。没有任何功能可以为您解决这个问题。您需要将整个内容保留为缺失,或者设置默认的第一个值(例如零)。
    【解决方案2】:

    我最终使用循环解决了这个问题:

    fillInTheBlanks <- function(S) {
      L <- !is.na(S)
      c(S[L][1], S[L])[cumsum(L)+1]
    }
    
    
    LOCF.DF <- function(xx)
    {
        # won't work well if the first observation is NA
    
        orig.class <- lapply(xx, class)
    
        new.xx <- data.frame(t( apply(xx,1, fillInTheBlanks) ))
    
        for(i in seq_along(orig.class))
        {
            if(orig.class[[i]] == "factor") new.xx[,i] <- as.factor(new.xx[,i])
            if(orig.class[[i]] == "numeric") new.xx[,i] <- as.numeric(new.xx[,i])
            if(orig.class[[i]] == "integer") new.xx[,i] <- as.integer(new.xx[,i])   
        }
    
        #t(na.locf(t(a)))
    
        return(new.xx)
    }
    
    a <- data.frame(rep("a",4), 1:4,1:4, c(1,NA,NA,NA))
    LOCF.DF(a)
    

    【讨论】:

      【解决方案3】:

      这个问题很老,但对于后代......最好的解决方案是使用 data.table 包与 roll=T。

      【讨论】:

      • 用例子填写
      【解决方案4】:

      您可以使用lapply() 代替apply(),然后将结果列表转换为data.frame

      LOCF <- function(x) {
          # Last Observation Carried Forward (for a left to right series)
          LOCF <- max(which(!is.na(x))) # the location of the Last Observation to Carry Forward
          x[LOCF:length(x)] <- x[LOCF]
          return(x)
      }
      
      a <- data.frame(rep("a",4), 1:4, 1:4, c(1, NA, NA, NA))
      a
      data.frame(lapply(a, LOCF))
      

      【讨论】:

        【解决方案5】:

        有很多包实现了这个功能。 (基本功能相同,但附加选项有所不同)

        • 时空::na.locf
        • imputeTS::na.locf
        • zoo::na.locf
        • xts::na.locf

        【讨论】:

        • tidyverse 也有一个等价的 fill() 函数。在 data.table 中有一些快速的东西会很棒。
        【解决方案6】:

        如果您不想为 na.locf 函数加载像 zoo 这样的大包,这里有一个简短的解决方案,如果输入向量中有一些前导 NA,也可以使用。

        na.locf <- function(x) {
          v <- !is.na(x)
          c(NA, x[v])[cumsum(v)+1]
        }
        

        【讨论】:

        • 我最喜欢这个解决方案。如果您想将其应用于data.frame,就像在原始问题中一样,您可以通过a[]=lapply(a,na.locf) 使用它。
        【解决方案7】:

        添加新的tidyr::fill()函数,用于将列中的最后一个观察结果继续填写NAs:

        a <- data.frame(col1 = rep("a",4), col2 = 1:4, 
                        col3 = 1:4, col4 = c(1,NA,NA,NA))
        a
        #   col1 col2 col3 col4
        # 1    a    1    1    1
        # 2    a    2    2   NA
        # 3    a    3    3   NA
        # 4    a    4    4   NA
        
        a %>% tidyr::fill(col4)
        #   col1 col2 col3 col4
        # 1    a    1    1    1
        # 2    a    2    2    1
        # 3    a    3    3    1
        # 4    a    4    4    1
        

        【讨论】:

          猜你喜欢
          • 2017-02-11
          • 2021-06-27
          • 1970-01-01
          • 2016-06-21
          • 2016-09-02
          • 2021-09-25
          • 1970-01-01
          • 1970-01-01
          • 2019-08-26
          相关资源
          最近更新 更多