【问题标题】:Joining two dataframes by concatenating columns通过连接列连接两个数据框
【发布时间】:2017-09-26 19:33:06
【问题描述】:

我有两个具有相同结构的数据框 - 都有两个 ID 列和 25 个字符串数据列。当 ID 匹配时,我想将两者连接起来并连接数据列中的字符串。所以,例如:

df_1:

id_1    id_2    col_1    col2    ...    col_25
a1      b1      A        A       ...    <NA>
a1      b2      A        <NA>    ...    A
a2      b1      <NA>     <NA>    ...    A

df_2:

id_1    id_2    col_1    col2    ...    col_25
a1      b1      B        <NA>    ...    <NA>
a1      b2      <NA>     B       ...    B
a1      b3      B        <NA>    ...    B

结合起来,这应该给

df_combined:

id_1    id_2    col_1    col2    ...    col_25
a1      b1      A, B     A       ...    <NA>
a1      b2      A        B       ...    A, B
a1      b3      B        <NA>    ...    B
a2      b1      <NA>     <NA>    ...    A

当我尝试使用联接或合并时,它会重复除 ID 列之外的所有内容(因此我最终得到 50 个数据列)。我需要使用其他东西吗?

谢谢!

【问题讨论】:

  • rbind 2 个数据帧,然后按 id 分组,遍历列并粘贴。看到这个帖子group by paste for one column
  • 如果您提供“即用型数据”,ppl 很乐意为您提供帮助。尽管问题很清楚。 +1

标签: r dataframe


【解决方案1】:

如果你没有任何空字符串,你可以这样做:

library(dplyr)    
bind_rows(df_1,df_2) %>%
  group_by(id_1,id_2) %>%
  summarize_all(~ paste(na.omit(.x),collapse=", ")) %>%
  `[<-`(.=="",value=NA)

使用magrittr,您可以避免不那么漂亮的'[&lt;-',并将其替换为inset

library(magrittr)
bind_rows(df_1,df_2) %>%
  group_by(id_1,id_2) %>%
  summarize_all(~ paste(na.omit(.x),collapse=", ")) %>%
  inset(.=="",value=NA)

【讨论】:

  • inset 的好 1。我不知道这个功能!看起来很方便!
  • 哎呀,我只是将其删除以避免 magrittr :),我会将其作为替代解决方案放回去
  • 呵呵。是的,你应该把它放在那里:)
  • 我认为 ifelse 经常被过度使用,而 inset 是合乎逻辑的做法,所以一些宣传不会受到伤害
  • 我讨厌ifelse。我尽量避免它(因此我更喜欢replace
【解决方案2】:

有一个替代解决方案使用melt()dcast() 来重塑数据:

library(data.table)
rbind(setDT(df_1), setDT(df_2))[
  , melt(.SD, measure.var = patterns("col"), na.rm = TRUE)][
    , dcast(.SD, id_1 + id_2 ~ variable, toString, fill = NA)]
   id_1 id_2 col_1 col2 col_25
1:   a1   b1  A, B    A     NA
2:   a1   b2     A    B   A, B
3:   a1   b3     B   NA      B
4:   a2   b1    NA   NA      A

数据

df_1 <- fread(
  "id_1    id_2    col_1    col2    ...    col_25
a1      b1      A        A       ...    <NA>
a1      b2      A        <NA>    ...    A
a2      b1      <NA>     <NA>    ...    A",
  drop = 5L, na.strings = "<NA>"
)

df_2 <- fread(
  "id_1    id_2    col_1    col2    ...    col_25
a1      b1      B        <NA>    ...    <NA>
a1      b2      <NA>     B       ...    B
a1      b3      B        <NA>    ...    B",
  drop = 5L, na.strings = "<NA>"
)

【讨论】:

    【解决方案3】:

    详细说明@zx8754评论的想法,并使用dplyr包,

    library(dplyr)
    
    df1 %>% 
     bind_rows(df2) %>% 
     mutate_at(vars(-contains('id')), funs(replace(., is.na(.), ''))) %>% 
     group_by(id_1, id_2) %>% 
     summarise_all(funs(trimws(paste(., collapse = ' ')))) %>% 
     mutate_all(funs(replace(., . == '', NA)))
    

    给出,

    # A tibble: 4 x 5
    # Groups:   id_1 [2]
       id_1  id_2 col_1  col2 col_25
      <chr> <chr> <chr> <chr>  <chr>
    1    a1    b1   A B     A   <NA>
    2    a1    b2     A     B    A B
    3    a1    b3     B  <NA>      B
    4    a2    b1  <NA>  <NA>      A
    

    注意:

    1. 以上脚本假定您的 NA 是实际的 NA(不是字符)
    2. 你的变量是as.character

    数据

    dput(df1)
    structure(list(id_1 = c("a1", "a1", "a2"), id_2 = c("b1", "b2", 
    "b1"), col_1 = c("A", "A", NA), col2 = c("A", NA, NA), col_25 = c(NA, 
    "A", "A")), .Names = c("id_1", "id_2", "col_1", "col2", "col_25"
    ), row.names = c(NA, -3L), class = "data.frame")
    > dput(df2)
    structure(list(id_1 = c("a1", "a1", "a1"), id_2 = c("b1", "b2", 
    "b3"), col_1 = c("B", NA, "B"), col2 = c(NA, "B", NA), col_25 = c(NA, 
    "B", "B")), .Names = c("id_1", "id_2", "col_1", "col2", "col_25"
    ), row.names = c(NA, -3L), class = "data.frame")
    

    【讨论】:

      猜你喜欢
      • 2018-03-08
      • 1970-01-01
      • 1970-01-01
      • 2019-01-05
      • 2018-03-16
      • 2021-11-19
      • 2021-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多