【问题标题】:Merging columns and adding NA where there is no value合并列并在没有值的地方添加 NA
【发布时间】:2018-07-27 07:38:20
【问题描述】:

我想合并来自不同数据帧的不同长度的 19 列并进行比较。这是一个例子:

df1: 
PA0001
PA0002
PA0003
PA0004
PA0005

df2: 
PA0001
PA0003
PA0006
PA0007


df3: 
PA0001
PA0007

等等……

输出是这样的:

PA0001  | PA0001 | PA0001
PA0002  |  NA    | NA
PA0003  | PA0003 | NA                   
PA0004  | NA     | NA
PA0005  | NA     | NA
NA      | PA0006 | NA
NA      | PA0007 | PA0007

我使用了compare 或merge 函数,但我没有得到好的结果。我试过用这个问题的功能:Link

但我得到了这个错误:

Error in attributes(.Data) <- c(attributes(.Data), attrib) : 
  'names' attribute [5254] must be the same length as the vector [2]

这是你的例子:

test1 <- data.frame(c("PA0001","PA0002","PA0003","PA0004","PA0005","PA0006"))
test2 <- data.frame(c("PA0001","PA0002","PA0004","PA0005","PA0007"))
test3 <- data.frame(c("PA0001","PA0004","PA0005","PA0007", "PA0008"))

非常感谢。

【问题讨论】:

  • 请阅读您阅读的问题的答案。 ...stringsAsFactors = FALSE。你必须强制你的列来改变字符。
  • @jogo 我做到了,我得到了这个错误Error in attributes(.Data) &lt;- c(attributes(.Data), attrib) : 'names' attribute [5254] must be the same length as the vector [2] 只使用一列并使用不同的名称。
  • 对我来说,答案stackoverflow.com/a/43266762/5414452 与df1 = data.frame(TEST1=c("PA0001","PA0002","PA0003","PA0004","PA0005","PA0006"), stringsAsFactors = FALSE) 一起使用,依此类推
  • 您创建的示例和您展示的输入/输出不同

标签: r merge multiple-columns


【解决方案1】:

如果我们需要 OP 预期的输出,请将数据集放在 list 中,rbind list 元素,同时使用 rbindlist 创建一个“grp”列,然后将 dcast 从“long”到'wide' 同时通过matching 'id' 与'id' 的unique 元素在公式中创建序列列

library(data.table)
dcast(rbindlist(list(test1, test2, test3), idcol = 'grp'),
         match(id, unique(id)) ~ paste0("col", grp))[, id := NULL][]
#     col1   col2   col3
#1: PA0001 PA0001 PA0001
#2: PA0002     NA     NA
#3: PA0003 PA0003     NA
#4: PA0004     NA     NA
#5: PA0005     NA     NA
#6:     NA PA0006     NA
#7:     NA PA0007 PA0007

或者作为@jogo拆分代码以使其更清晰,在第一步中,rbindlist中的所有数据集同时通过指定idcol参数创建'grp'列

t_all <- rbindlist(list(test1, test2, test3), idcol='grp');

然后将dcast 转换为“宽”格式并将“id”列分配给NULL

dcast(t_all, id ~ grp, value.var='id')[, id := NULL][]

数据

test1 <- data.frame(id = c("PA0001","PA0002","PA0003","PA0004","PA0005"))
test2 <- data.frame(id = c("PA0001","PA0003","PA0006","PA0007"))
test3 <- data.frame(id = c("PA0001", "PA0007"))

【讨论】:

    【解决方案2】:

    这是一个基本的 R 解决方案:

    x <- lapply(list(test1, test2, test3), function(x) as.character(x[,1]))
    xuni <- unique(unlist(x))
    one_set <- function(i) { 
        idx <- which(is.na(match(xuni, x[[i]])))
        ans <- xuni
        ans[idx] <- NA
        return(ans)
    }
    res <- data.frame(
        test1=one_set(1),
        test2=one_set(2),
        test3=one_set(3),
        stringsAsFactors=FALSE
    )
    res
    
       test1  test2  test3
    1 PA0001 PA0001 PA0001
    2 PA0002 PA0002   <NA>
    3 PA0003   <NA>   <NA>
    4 PA0004 PA0004 PA0004
    5 PA0005 PA0005 PA0005
    6 PA0006   <NA>   <NA>
    7   <NA> PA0007 PA0007
    8   <NA>   <NA> PA0008
    

    第一行将因子转换为字符,并将 data.frame 转换为每个 data.frame 中元素的列表x。

    第二行标识所有观察值。

    函数one_set 采用一个索引(要查看x 的哪个元素)并返回所需的输出列。

    【讨论】:

      【解决方案3】:

      您可以尝试tidyverse 解决方案

      library(tidyverse)
      d1 <- read.table(text="PA0001
                 PA0002
                 PA0003
                 PA0004
                 PA0005")
      d2 <- read.table(text="PA0001
                 PA0003
                 PA0006
                 PA0007")
      d3 <- read.table(text="PA0001
                 PA0007")
      
      list(d1, d2, d3) %>% 
        bind_rows(.id = "df") %>% 
        mutate(n = TRUE) %>% 
        spread(df, n, fill = FALSE)
            V1     1     2     3
      1 PA0001  TRUE  TRUE  TRUE
      2 PA0002  TRUE FALSE FALSE
      3 PA0003  TRUE  TRUE FALSE
      4 PA0004  TRUE FALSE FALSE
      5 PA0005  TRUE FALSE FALSE
      6 PA0006 FALSE  TRUE FALSE
      7 PA0007 FALSE  TRUE  TRUE
      

      想法是将所有data.frames包含在一个列表中,然后将它们逐行绑定,添加逻辑TRUE并使用tidyr的spread函数获取结果。 当然,您也可以使用以下方法获得预期的输出:

      list(d1, d2, d3) %>% 
        bind_rows(.id="df") %>% 
        mutate(n=V1) %>% 
        spread(df, n) %>% 
        select(-1)
             1      2      3
      1 PA0001 PA0001 PA0001
      2 PA0002   <NA>   <NA>
      3 PA0003 PA0003   <NA>
      4 PA0004   <NA>   <NA>
      5 PA0005   <NA>   <NA>
      6   <NA> PA0006   <NA>
      7   <NA> PA0007 PA000
      

      在baseR 你可以试试:

      Reduce(function(x, y) merge(x, y, by="V1", all.x = TRUE, all.y = TRUE),
                    lapply(list(d1, d2, d3), function(x) cbind(x,V2=x$V1)))[,-1]
          V2.x   V2.y     V2
      1 PA0001 PA0001 PA0001
      2 PA0002   <NA>   <NA>
      3 PA0003 PA0003   <NA>
      4 PA0004   <NA>   <NA>
      5 PA0005   <NA>   <NA>
      6   <NA> PA0006   <NA>
      7   <NA> PA0007 PA0007
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-10
        • 2013-10-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多