【问题标题】:Conditional concatenate columns条件连接列
【发布时间】:2021-06-11 16:24:17
【问题描述】:

数据如下所示:

  Language Files   LOC
1      C++  4009     0
2     Java     0   876
3   Python    35   200

我想添加第四列,如下所示。如果 Files/LOC 中有非零值,则新列将包含该值和列名。例如

  Language Files   LOC                          Final
1      C++  4009     0 C++: It's Files:4009
2     Java     0   876 Java: It's LOC:876
3   Python    35   200 Python: It's Files:35, LOC:200
4        R     0     0 R: Nothing here.

这几乎是答案,但在 dim() 4701x158 的数据帧上非常慢:

colList <- list('Files', 'LOC')
for (i in 1:nrow(df)) {
    row <- df[i,]
    for (j in 1:length(colList)) {
        type <- colList[[j]][1]
        if (row[[type]] > 0) {
            df[i,][['Final']] <- paste(row[['Final']], '<br>', type, ': ', row[[type]], sep = '')
        }
    }
}

【问题讨论】:

    标签: r dataframe concatenation


    【解决方案1】:

    使用apply 与您的for 循环没有太大区别。我们可以使用Reduce(实际上内部也使用for循环,但不同)。

    Final <- cbind(df[, 1], sapply(1:2, function(j) {
      paste0(" ", names(df)[j + 1], ":", df[, j + 1])
    }))
    Final[grep(":0", Final)] <- ""
    res <- cbind(df, Final=Reduce(paste0, as.data.frame(Final)))
    res
    #   Language Files LOC                   Final
    # 1      C++  4009   0          C++ Files:4009
    # 2     Java     0 876            Java LOC:876
    # 3   Python    35 200 Python Files:35 LOC:200
    # 4        R     0   0                       R
    

    基准测试

    DF <- df[sample(nrow(df), 1e3, replace=T), ]  ## make a bigger df
    
    reduce1 <- function() {
      Final <- cbind(DF[, 1], sapply(1:2, function(j) {
        paste0(" ", names(DF)[j + 1], ":", DF[, j + 1])
      }))
      Final[grep(":0", Final)] <- ""
      Reduce(paste0, as.data.frame(Final))
    }
    
    apply1 <- function() {
      cols <- names(DF)[-1]
      paste(DF$Language, apply(DF[-1], 1, function(x) {
        inds <- x > 0
        paste(cols[inds], x[inds], sep = ':', collapse = ' ')
      }))
    }
    
    microbenchmark::microbenchmark(reduce1(), apply1(), control=list(warmup=100L))
    # Unit: milliseconds
    #      expr       min        lq     mean    median        uq      max neval cld
    # reduce1()  1.719615  1.751507  1.91386  1.816695  1.852541 12.01664   100  a 
    #  apply1() 10.722591 10.926188 11.43564 11.029519 11.158617 18.92393   100   b
    

    【讨论】:

      【解决方案2】:

      你可以使用apply

      cols <- names(df)[-1]
      df$Final <- paste(df$Language, apply(df[-1], 1, function(x) {
        inds <- x > 0
        paste(cols[inds], x[inds], sep = ':', collapse = ' ')
      }))
      
      df
      
      #  Language Files LOC                   Final
      #1      C++  4009   0          C++ Files:4009
      #2     Java     0 876            Java LOC:876
      #3   Python    35 200 Python Files:35 LOC:200
      #4        R     0   0                      R 
      

      数据

      df <- structure(list(Language = c("C++", "Java", "Python", "R"), Files = c(4009L,
      0L, 35L, 0L), LOC = c(0L, 876L, 200L, 0L)), 
      class = "data.frame", row.names = c("1", "2", "3", "4"))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-07-09
        • 2023-03-09
        • 2022-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-18
        相关资源
        最近更新 更多