【问题标题】:How to merge columns by duplicate rows in awk/unix/R [closed]如何通过 awk/unix/R 中的重复行合并列 [关闭]
【发布时间】:2020-06-23 23:00:35
【问题描述】:

我有一个制表符分隔符输入文件,如下所示:

Input:
4444    a   b   c   1  4444 1   4444
9990    a   b   c   1  6666 1   2222
9990    a   b   c   2  6667,6668    1   2223
1700    a   b   c   1   3333    1   8786
1700    a   b   c   1   4444    1   8787
1700    a   b   c   1   5555    1   8788

对于 $1,$2,$3,$4 中的每个唯一字符串,我需要添加 $5 并合并 $6 并添加 $7 并合并 $8,以便输出如下所示:

Output:
4444    a   b   c   1   4444    1   4444
9990    a   b   c   3   6666,6667,6668  2   2222,2223
1700    a   b   c   3   3333,4444,5555  3   8786,8787,8788

我认为这可能有一个现有的解决方案。有人可以在 awk/unix/R 中提供解决方案吗

【问题讨论】:

  • 哇,这不是我所期望的最接近的原因。诚然,并没有一个与idownvotedbecau.se/noattempt 匹配的很好的如此接近的原因(我没有 DV,但是......我认为这不是不合理的)。
  • GNU datamash 解决方案:datamash -g 1,2,3,4 sum 5 collapse 6 sum 7 collapse 8 < input.tsv (取决于您的示例中相邻的所有组;如果不添加 -s 到选项中)

标签: r awk merge duplicates


【解决方案1】:

使用 Rdata.table

library(data.table)

# example data
Input <- fread("
4444    a   b   c   1  4444 1   4444
9990    a   b   c   1  6666 1   2222
9990    a   b   c   2  6667,6668    1   2223
1700    a   b   c   1   3333    1   8786
1700    a   b   c   1   4444    1   8787
1700    a   b   c   1   5555    1   8788")

Input[, .(x5 = sum(V5), 
          x6 = toString(V6),
          x7 = sum(V7), 
          x8 = toString(V8)), by = V1:V4]

#      V1 V2 V3 V4 x5               x6 x7               x8
# 1: 4444  a  b  c  1             4444  1             4444
# 2: 9990  a  b  c  3  6666, 6667,6668  2       2222, 2223
# 3: 1700  a  b  c  3 3333, 4444, 5555  3 8786, 8787, 8788

【讨论】:

    【解决方案2】:

    也许您可以尝试以下 base R 代码,使用 merge + aggregate,即,

    dfout <- merge(aggregate(cbind(V5,V7)~V1+V2+V3+V4,df,sum),
                   aggregate(cbind(V6,V8)~V1+V2+V3+V4,df,paste0, collapse = ","))
    

    这样

    > dfout
        V1 V2 V3 V4 V5 V7             V6             V8
    1 1700  a  b  c  3  3 3333,4444,5555 8786,8787,8788
    2 4444  a  b  c  1  1           4444           4444
    3 9990  a  b  c  3  2  6666,666,6668      2222,2223
    

    数据

    df <- structure(list(V1 = c(4444L, 9990L, 9990L, 1700L, 1700L, 1700L
    ), V2 = c("a", "a", "a", "a", "a", "a"), V3 = c("b", "b", "b", 
    "b", "b", "b"), V4 = c("c", "c", "c", "c", "c", "c"), V5 = c(1L, 
    1L, 2L, 1L, 1L, 1L), V6 = c("4444", "6666", "666,6668", "3333", 
    "4444", "5555"), V7 = c(1L, 1L, 1L, 1L, 1L, 1L), V8 = c(4444L, 
    2222L, 2223L, 8786L, 8787L, 8788L)), class = "data.frame", row.names = c(NA, 
    -6L))
    

    【讨论】:

    • 解决方案报错:Error in as.data.frame.default(data, optional = TRUE) : cannot coerce class ‘"function"’ to a data.frame
    • chas,您似乎将数据命名为其他名称...df,如果未定义为数据,则在 R 中是一个普通函数。
    • @chas 你在我的回答中使用了数据吗?
    • 现在可以使用了。是的 df 在我的情况下是另外一回事。
    • @chas 你可以将我的代码中数据框的名字改成你需要的名字
    【解决方案3】:

    dplyr方法补充其他:

    dat <- read.table(header=FALSE, stringsAsFactors=FALSE, text="
    4444    a   b   c   1  4444 1   4444
    9990    a   b   c   1  6666 1   2222
    9990    a   b   c   2  6667,6668    1   2223
    1700    a   b   c   1   3333    1   8786
    1700    a   b   c   1   4444    1   8787
    1700    a   b   c   1   5555    1   8788")
    library(dplyr)
    dat %>%
      group_by(V1) %>%
      summarise_all(~ paste(sort(unique(.)), collapse = ",")) %>%
      mutate(V5 = sapply(strsplit(V5, ","), function(a) sum(as.integer(a))))
    # # A tibble: 3 x 8
    #      V1 V2    V3    V4    V5    V6             V7    V8            
    #   <int> <chr> <chr> <chr> <int> <chr>          <chr> <chr>         
    # 1  1700 a     b     c     1     3333,4444,5555 1     8786,8787,8788
    # 2  4444 a     b     c     1     4444           1     4444          
    # 3  9990 a     b     c     3     6666,6667,6668 1     2222,2223     
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-01
      • 2021-11-23
      • 2020-08-31
      • 1970-01-01
      • 1970-01-01
      • 2021-11-12
      • 1970-01-01
      相关资源
      最近更新 更多