合并两个数据框或表格

3

我有以下数据框:

a <- data.frame(Test=1:4,
            TestA=5:6)
> a
    Test TestA
1    1     5
2    2     6
3    3     5
4    4     6


b <- data.frame(TEST=1:10,
            TestB=11:20)

> b
    TEST TestB
1     1    11
2     2    12
3     3    13
4     4    14
5     5    15
6     6    16
7     7    17
8     8    18
9     9    19
10   10    20

我希望你能将它们结合起来,使结果看起来像这样:
    Test TestA TEST   TestB
1     1     5    1      11
2     2     6    2      12
3     3     5    3      13
4     4     6    4      14
5     0     0    5      15
6     0     0    6      16
7     0     0    7      17
8     0     0    8      18
9     0     0    9      19
10    0     0   10      20

也就是说,将未匹配的行与填充零相结合。

我相信存在一个简单的解决方案,如果有一种方法可以使用dplyr来实现那就太好了。


为什么你的结果数据集中的TestA列不是5,6,5,6,0,.... - AntoniosK
抱歉,应该是 5,6,5,6,0,... - Christian
6个回答

3
你可以使用 merge() 函数将两个数据框合并。
df<-merge(x=a,y=b,by.x="Test",by.y = "TEST",all= T)

以上产生:
   Test TestA TestB
1     1     5    11
2     2     6    12
3     3     5    13
4     4     6    14
5     5    NA    15
6     6    NA    16
7     7    NA    17
8     8    NA    18
9     9    NA    19
10   10    NA    20

如果您想将“Test”和“TEST”分开,可以为两者创建一个ID列,并将“by.x”和“by.y”替换为该ID变量。
要使用“df $ TestA [is.na(TestA)] <- 0”将NA替换为0。如果要保留“Test”和“TEST”,则也适用于“Test”。

非常感谢你 - Christian
不客气。如果解决方案对您有用,您可以选择勾选答案来关闭查询。 - Luke Hayden

1
使用data.table,您可以:
  1. b中预填0,然后
  2. a更新加入值

例如...

# input
a <- data.frame(Test=1:4, TestA=5:6)
b <- data.frame(TEST=1:10, TestB=11:20)
library(data.table)
setDT(a); setDT(b)

# prefill
b[, c("Test", "TestA") := 0L]

# update join
b[a, on=.(TEST = Test), c("Test", "TestA") := .(i.Test, i.TestA)]

    TEST TestB Test TestA
 1:    1    11    1     5
 2:    2    12    2     6
 3:    3    13    3     5
 4:    4    14    4     6
 5:    5    15    0     0
 6:    6    16    0     0
 7:    7    17    0     0
 8:    8    18    0     0
 9:    9    19    0     0
10:   10    20    0     0

这会修改b而不是创建一个新表。这适用于您的示例,但如果您需要“完全连接”(其中b没有您想要在最终表中的完整行集),则另一个答案更合适。
另一方面,如果您的表具有真正的NAs,您不希望将其填充为零,则这比前几个答案更好(它们会覆盖所有NAs,而不仅仅是由于行在表的连接/合并/组合中不匹配而产生的那些)。
为了推广到更多的列,定义一个包含默认值的列表...
# input
a <- data.frame(Test=1:4, TestA=5:6)
b <- data.frame(TEST=1:10, TestB=11:20)

library(data.table)
setDT(a); setDT(b)    
defaults = list(Test = 0L, TestA = 0L)
new_cols = names(defaults)

# prefill defaults
b[, (new_cols) := defaults]

# update join
b[a, on=.(TEST = Test), (new_cols) := mget(sprintf("i.%s", new_cols))]

0

想要重复测试列并且希望0而不是NA,这有点不寻常,但按照您的要求来做如下:

library(dplyr)
b$Test <- b$TEST
c <- full_join(a,b, by="Test")
c$Test[is.na(c$TestA)] <-0
c$TestA[is.na(c$TestA)] <-0

0
df <- merge(a, b, by = 0, all = TRUE,sort = FALSE)[-1]
df[is.na(df)] <- 0
df
   Test TestA TEST TestB
1     1     5    1    11
2     2     6    2    12
3     3     5    3    13
4     4     6    4    14
5     0     0    5    15
6     0     0    6    16
7     0     0    7    17
8     0     0    8    18
9     0     0    9    19
10    0     0   10    20

太好了,谢谢!非常简单,这正是我在寻找的。:-) - Christian

0
# example datasets
a <- data.frame(Test=1:4,
                TestA=5:6)

b <- data.frame(TEST=1:10,
                TestB=11:20)

library(dplyr)

a %>%
  mutate(TEST = Test) %>%                        # duplicate Test column and give the name TEST
  full_join(b, by="TEST") %>%                    # full join 
  mutate_at(vars(Test, TestA), ~coalesce(.,0L))  # replace NAs with 0s for those two variables

#    Test TestA TEST TestB
# 1     1     5    1    11
# 2     2     6    2    12
# 3     3     5    3    13
# 4     4     6    4    14
# 5     0     0    5    15
# 6     0     0    6    16
# 7     0     0    7    17
# 8     0     0    8    18
# 9     0     0    9    19
# 10    0     0   10    20

你也可以使用mutate_all(~coalesce(.,0L)),但如果你知道NA只会存在于这两列中,就没有必要查找所有列的NA。

0
你可以使用包 sqldf
library(sqldf)
res <- sqldf("SELECT a.*, b.* FROM b LEFT JOIN a on a.test = B.test")
res[is.na(res)] <- 0
res
#    Test TestA TEST TestB
# 1     1     5    1    11
# 2     2     6    2    12
# 3     3     5    3    13
# 4     4     6    4    14
# 5     0     0    5    15
# 6     0     0    6    16
# 7     0     0    7    17
# 8     0     0    8    18
# 9     0     0    9    19
# 10    0     0   10    20

或者仅使用 SQL,利用函数 coalesce,正如 @G. Grothendieck 所提到的:

sqldf("SELECT coalesce(a.Test, 0) Test, coalesce(a.TestA, 0) TestA, b.* FROM b LEFT JOIN a using(test)")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接