在R数据框中填充缺失列的更快方法

3

有哪位R专家能提供更快的方法来完成以下操作吗?我的代码可以运行,但是处理一个由30,000列和12行构成的数据框需要1分钟时间。谢谢!

    sync.columns = function(old.data, new.colnames)
    {
      # Given a data frame and a vector of column names,
      # makes a new data frame containing exactly the named
      # columns in the specified order; any that were not
      # present are filled in as columns of zeroes.

      if (length(new.colnames) == ncol(old.data) && 
          all(new.colnames == colnames(old.data)))
      {
        old.data    # nothing to do
      }
      else
      {
        m = matrix(nrow=nrow(old.data),ncol=length(new.colnames))

        for (t in 1:length(new.colnames))
        {
          if (new.colnames[t] %in% colnames(old.data))
          {
            m[,t] = old.data[,new.colnames[t]]   # copy column
          }
          else
          {
            m[,t] = rep(0,nrow(m))   # fill with zeroes
          }
        }
        result = as.data.frame(m)
        rownames(result) = rownames(old.data)
        colnames(result) = new.colnames
        result
      }
    }

也许可以使用cbind函数?
1个回答

3

这看起来相当快。首先创建一个全是零的数据框,然后只替换你在旧数据中能找到的内容:

sync.columns <- function(old.data, new.colnames) {
   M  <- nrow(old.data)
   N  <- length(new.colnames)
   rn <- rownames(old.data)
   cn <- new.colnames
   new.data <- as.data.frame(matrix(0, M, N, dimnames = list(rn, cn)))
   keep.col <- intersect(cn, colnames(old.data))
   new.data[keep.col] <- old.data[keep.col]
   new.data
}

M <- 30000
x <- data.frame(b = runif(M), i = runif(M), z = runif(M))
rownames(x) <- paste0("z", 1:M)
system.time(y <- sync.columns(x, letters[1:12]))
#    user  system elapsed 
#   0.031   0.010   0.043

head(y)
#    a          b c d e f g h         i j k l
# z1 0 0.27994248 0 0 0 0 0 0 0.3785181 0 0 0
# z2 0 0.75291520 0 0 0 0 0 0 0.7414294 0 0 0
# z3 0 0.07036461 0 0 0 0 0 0 0.1543653 0 0 0
# z4 0 0.40748957 0 0 0 0 0 0 0.5564374 0 0 0
# z5 0 0.98769595 0 0 0 0 0 0 0.4277466 0 0 0
# z6 0 0.82117781 0 0 0 0 0 0 0.2034743 0 0 0
编辑:根据下面与原帖的评论,这里提供一个矩阵版本:
sync.columns <- function(old.data, new.colnames) {
  M  <- nrow(old.data)
  N  <- length(new.colnames)
  rn <- rownames(old.data)
  cn <- new.colnames
  new.data <- matrix(0, M, N, dimnames = list(rn, cn))
  keep.col <- intersect(cn, colnames(old.data))
  new.data[, keep.col] <- old.data[, keep.col]
  new.data
}

x <- t(as.matrix(x)) # a wide matrix
system.time(y <- sync.columns(x, paste0("z", sample(1:50000, 30000))))
#    user  system elapsed 
#   0.049   0.002   0.051 

谢谢,这将时间缩短到了25秒,而不是120秒,这是一个显著的改进。我希望能有1或2秒的速度(与读取那么大的数据集的read.csv相当)……还有其他的想法吗? - mc at uga dot edu
为什么是25秒?你看我的例子只需要40多毫秒。我们还需要知道什么?也许给我们展示一下 str(old.data) - flodel
哎呀!我的矩阵不是12宽x30000高,而是30000宽x12深。对此我感到非常抱歉。我有几个版本的程序,所以把矩阵搞混了。现在你已经向我展示了你的实现方式,我很想把它“倒回去”!但这可能没有帮助,因为那样我就需要同步行而不是列。通常情况下,行数多比列数多更好吗? - mc at uga dot edu
请注意,我的原始代码正在处理(创建)矩阵。我是否也应该将输入的数据框转换为矩阵? - mc at uga dot edu
矩阵版本非常出色(以毫秒计算)。谢谢! - mc at uga dot edu
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接