【问题标题】:cbind a dataframe with an empty dataframe - cbind.fill?cbind 一个带有空数据框的数据框 - cbind.fill?
【发布时间】:2011-12-19 05:19:30
【问题描述】:

我想我正在为cbind 寻找rbind.fill 的类似物(在Hadley 的plyr 包中)。我看了看,没有cbind.fill

我想做的是:

#set these just for this example
one_option <- TRUE
diff_option <- TRUE

return_df <- data.frame()

if (one_option) {
    #do a bunch of calculations, produce a data.frame, for simplicity the following small_df
    small_df <- data.frame(a=1, b=2)
    return_df <- cbind(return_df,small_df)
}

if (diff_option) {
    #do a bunch of calculations, produce a data.frame, for simplicity the following small2_df
    small2_df <- data.frame(l="hi there", m=44)
    return_df <- cbind(return_df,small2_df)
}

return_df

可以理解,这会产生错误:

Error in data.frame(..., check.names = FALSE) : 
arguments imply differing number of rows: 0, 1

我目前的解决方法是用return_df &lt;- data.frame(dummy=1) 替换行return_df &lt;- data.frame(),然后代码就可以工作了。然后我在最后从return_df 中删除虚拟对象。添加虚拟对象并运行上述代码后,我得到了

      dummy a b        l  m
1     1 1 2 hi there 44

然后我只需要摆脱假人,例如:

> return_df[,2:ncol(return_df)]
  a b        l  m
1 1 2 hi there 44

我确定我错过了一种更简单的方法。

编辑:我想我不是在寻找 cbind.fill,因为这意味着将在 cbind 之后创建一个 NA 值,这不是我想要的。

【问题讨论】:

  • 没有数据集和预期的输出,很难确切知道您想要什么。
  • @TylerRinker,你是对的。我确实描述了我当前的修复,但我没有明确说明我想要的结果是什么。我现在已经添加了这些信息。

标签: r dataframe cbind


【解决方案1】:

对于 cbind.fill 命名列表,其中名称重叠并且您希望按名称 cbind,Tyler 的答案可能会修改为以下内容:

cbind.fill <- function(...){
    nm <- list(...) 
    nm <- lapply(nm, as.matrix)
    names <- unique(do.call(c, lapply(nm, rownames)))
    res <- matrix(nrow = length(names), ncol = length(nm))
    rownames(res) <- names
    for(i in 1:length(nm))
      res[rownames(nm[[i]]),i] <- nm[[i]][,1]
    res
}

【讨论】:

    【解决方案2】:

    我们可以使用list 代替data.frame,并在最后将其转换为data.frame。例如:

    df = list()
    df2 = data.frame(col1 = 1:3, col2 = c('a','b','c'))
    df = as.data.frame(cbind(df, as.matrix(df2)))
    df
    
    #   col1 col2
    # 1    1    a
    # 2    2    b
    # 3    3    c
    

    【讨论】:

      【解决方案3】:

      ab 是数据帧时,以下应该可以正常工作:

      ab <- merge(a, b, by="row.names", all=TRUE)[,-1]
      

      或其他可能性:

      rows <- unique(c(rownames(a), rownames(b)))
      ab <- cbind(a[rows ,], b[rows ,])
      

      【讨论】:

        【解决方案4】:

        我们可以添加 id 列然后使用 merge

        df1 <- mtcars[1:5, 1:2]
        #                    mpg cyl id
        # Mazda RX4         21.0   6  1
        # Mazda RX4 Wag     21.0   6  2
        # Datsun 710        22.8   4  3
        # Hornet 4 Drive    21.4   6  4
        # Hornet Sportabout 18.7   8  5
        
        df2 <- mtcars[6:7, 3:4]
        #            disp  hp
        # Valiant     225 105
        # Duster 360  360 245
        
        #Add id column then merge
        df1$id <- seq(nrow(df1)) 
        df2$id <- seq(nrow(df2)) 
        
        merge(df1, df2, by = "id", all.x = TRUE, check.names = FALSE)
        #   id  mpg cyl disp  hp
        # 1  1 21.0   6  225 105
        # 2  2 21.0   6  360 245
        # 3  3 22.8   4   NA  NA
        # 4  4 21.4   6   NA  NA
        # 5  5 18.7   8   NA  NA
        

        【讨论】:

          【解决方案5】:

          使用rowr::cbind.fill

          rowr::cbind.fill(df1,df2,fill = NA)
             A B
          1  1 1
          2  2 2
          3  3 3
          4  4 4
          5  5 5
          6 NA 6
          

          【讨论】:

          • 看起来rowr 已被弃用?
          【解决方案6】:

          我只是发现了一个技巧,当我们想将列添加到一个空数据帧中时,只需在第一次 rbind 时,而不是稍后 cbind

              newdf <- data.frame()
              # add the first column
              newdf <- rbind(newdf,data.frame("col1"=c("row1"=1,"row2"=2)))
              # add the second column
              newdf <- cbind(newdf,data.frame("col2"=c("row1"=3,"row2"=4)))
              # add more columns
              newdf <- cbind(newdf,data.frame("col3"=c("row1"=5,"row2"=6)))
              # result
              #     col1 col2 col3
              #row1    1    3    5
              #row2    2    4    6
          

          我不知道为什么,但它对我有用。

          【讨论】:

            【解决方案7】:

            我建议修改泰勒的回答。我的函数允许 cbind-ing 使用向量的 data.frames 和/或矩阵,而不会丢失列名,因为它发生在 Tyler 的解决方案中

            cbind.fill <- function(...){
              nm <- list(...) 
              dfdetect <- grepl("data.frame|matrix", unlist(lapply(nm, function(cl) paste(class(cl), collapse = " ") )))
              # first cbind vectors together 
              vec <- data.frame(nm[!dfdetect])
              n <- max(sapply(nm[dfdetect], nrow)) 
              vec <- data.frame(lapply(vec, function(x) rep(x, n)))
              if (nrow(vec) > 0) nm <- c(nm[dfdetect], list(vec))
              nm <- lapply(nm, as.data.frame)
            
              do.call(cbind, lapply(nm, function (df1) 
                rbind(df1, as.data.frame(matrix(NA, ncol = ncol(df1), nrow = n-nrow(df1), dimnames = list(NULL, names(df1))))) )) 
            }
            
            cbind.fill(data.frame(idx = numeric()), matrix(0, ncol = 2), 
                       data.frame(qwe = 1:3, rty = letters[1:3]), type = "GOOD", mark = "K-5")
            #       idx V1 V2 qwe rty type mark
            #     1  NA  0  0   1   a GOOD  K-5
            #     2  NA NA NA   2   b GOOD  K-5
            #     3  NA NA NA   3   c GOOD  K-5
            

            【讨论】:

              【解决方案8】:

              这是一个 cbind 填充:

              cbind.fill <- function(...){
                  nm <- list(...) 
                  nm <- lapply(nm, as.matrix)
                  n <- max(sapply(nm, nrow)) 
                  do.call(cbind, lapply(nm, function (x) 
                      rbind(x, matrix(, n-nrow(x), ncol(x))))) 
              }
              

              让我们试试吧:

              x<-matrix(1:10,5,2)
              y<-matrix(1:16, 4,4)
              z<-matrix(1:12, 2,6)
              
              cbind.fill(x,y)
              cbind.fill(x,y,z)
              cbind.fill(mtcars, mtcars[1:10,])
              

              我想我是从某个地方偷来的。

              从这里编辑 STOLE:LINK

              【讨论】:

              • 谢谢泰勒。但是我有一个数据框而不是一个矩阵,我认为这确实会破坏这个实现。另外,我编辑了我的帖子,因为我认为我弄错了——我不认为我想要一个 cbind.fill,因为那会创建一个 NA,而我什么都不想创建。
              • 我编辑了我的帖子以使代码在数据帧和矩阵上都可以工作。我认为不可能输出不等行的数据框。根据定义,数据框是等长 n 的列表,因此不可能出现不是矩形的数据框。
              • @Xu Wang,函数有as.data.frame()和as.matrix(),所以你有data.frame没有matrix也没问题。
              • 只是一个简短的站点注释:代码也可以在 Gist 上找到。
              【解决方案9】:
              qpcR 包中的

              cbind.na 可以做到这一点。

                  install.packages("qpcR")
                  library(qpcR)
                  qpcR:::cbind.na(1, 1:7)
              

              【讨论】:

              • 函数 cbind.na 似乎不再是包 qpcR 的一部分
              【解决方案10】:

              虽然我认为 Tyler 的解决方案是直接的,也是这里最好的,但我只是提供另一种方式,使用我们已经拥有的 rbind.fill()

              require(plyr) # requires plyr for rbind.fill()
              cbind.fill <- function(...) {                                                                                                                                                       
                transpoted <- lapply(list(...),t)                                                                                                                                                 
                transpoted_dataframe <- lapply(transpoted, as.data.frame)                                                                                                                         
                return (data.frame(t(rbind.fill(transpoted_dataframe))))                                                                                                                          
              } 
              

              【讨论】:

              • 谢谢麦克斯!我喜欢你的解决方案。我会指出(对于未来的读者)这个解决方案需要加载包plyr,其中 Tyler 不依赖任何额外的包(我认为)。
              • @Xu Wang,添加了 require(plyr) 语句。
              • 请注意,Max 的解决方案返回一个数据框,而我的解决方案返回一个矩阵。如果你真的希望函数返回一个矩阵,你可以用as.data.frame() 包裹最后一行
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-02-01
              • 2021-01-12
              相关资源
              最近更新 更多