【问题标题】:Merging two dataframes based on first two columns with the same information arranged differently in R基于前两列合并两个数据帧,在R中以不同方式排列相同的信息
【发布时间】:2019-04-05 20:55:10
【问题描述】:

我想根据前两列及其值合并两个数据框,但是,这些列中的这些值可以根据数据集在列之间切换。所以dplyr包中的mergeleft_join函数看不出成对信息是一样的。

为了更好的解释,我在这里定义了两个假设的数据集:

tree.dat1 = data.frame(tree1 = factor(c(rep(33,3),rep(22,2),11)),
+                       tree2 = factor(c(22,11,44,11,44,44)),
+                       value = c(0.02, rep(0.03,3), rep(0.01,2)))

> tree.dat1
   tree1 tree2 value
1    33    22  0.02
2    33    11  0.03
3    33    44  0.03
4    22    11  0.03
5    22    44  0.01
6    11    44  0.01

tree.dat2 = data.frame(tree1 = factor(c(rep(11,3),rep(33,2),22)),
+                        tree2 = factor(c(22,33,44,22,44,44)),
+                        value1 = c(rep(3,0.05),0.02,rep(0.03,2)))
> tree.dat2
  tree1 tree2 value1
1    11    22   0.02
2    11    33   0.03
3    11    44   0.03
4    33    22   0.02
5    33    44   0.03
6    22    44   0.03

如您所见,前两列的成对是相同的,但是它们的顺序不同。所以我想通过在前两列中使用这些信息并在这些数据集中保留第三列来创建一个新的数据集。

所以:

> tree.dat3 = left_join(tree.dat1,tree.dat2, by = c("tree1","tree2"))
> tree.dat3
   tree1 tree2 value value1
1    33    22  0.02   0.02
2    33    11  0.03     NA
3    33    44  0.03   0.03
4    22    11  0.03     NA
5    22    44  0.01   0.03
6    11    44  0.01   0.03

我最后有两个 NAs 值,但是,当我检查成对表时,我可以在 tree.dat1 数据集中看到成对的 33 - 11(或 22 - 11)的信息。

所以预期的输出是:

   tree1 tree2 value value1
1    33    22  0.02   0.02
2    33    11  0.03   0.03
3    33    44  0.03   0.03
4    22    11  0.03   0.02
5    22    44  0.01   0.03
6    11    44  0.01   0.03

所以我可能正在寻找其他方法来合并两个数据框以检查成对信息而不是两列中的因子水平。因为 33 - 11 和 11 - 33 相同,但第三列的值不同。我想知道一种适合大型数据集的方法。有什么建议吗?

【问题讨论】:

  • 你能显示预期的输出吗
  • 我已经用预期的输出编辑了问题。

标签: r dataframe merge dplyr


【解决方案1】:

由于连接的顺序无关紧要,让我们创建一个TreeID 列,对tree1tree2 进行排序,以便数字对始终以相同的顺序出现。

如果您的数据未编码为factor,这会更容易,因为将min/max 作为一个因子不起作用,您必须强制转换为字符,然后转换为数字才能使其正常工作。如果您需要对源数据执行此操作,as.numeric(as.character(tree.dat1$tree)) 可以解决问题。您可以在不转换为numeric 的情况下获取character 向量的最大值,但我不希望这样做,因为max("11","2") 的性能不如您预期的那样。

library(tidyverse)
library(stringr)

tree.dat1 = data.frame(tree1 = c(rep(33,3),rep(22,2),11),
                       tree2 = c(22,11,44,11,44,44),
                       value = c(0.02, rep(0.03,3), rep(0.01,2)))

tree.dat2 = data.frame(tree1 = c(rep(11,3),rep(33,2),22),
                       tree2 = c(22,33,44,22,44,44),
                        value1 = c(rep(3,0.05),0.02,rep(0.03,2)))

通过组合tree1tree2 的最小值和最大值来构造TreeID。我们使用rowwise() 来获取每一行而不是每一列的最大值和最小值。

tree.dat1 <- tree.dat1 %>% rowwise() %>% 
  mutate(TreeID= str_c(min(tree1, tree2), max(tree1,tree2)))

tree.dat2 <- tree.dat2 %>% rowwise() %>% 
  mutate(TreeID= str_c(min(tree1, tree2), max(tree1,tree2)))

left_join(tree.dat1, tree.dat2, by = "TreeID")


Source: local data frame [6 x 7]
Groups: <by row>

# A tibble: 6 x 7
  tree1.x tree2.x value TreeID tree1.y tree2.y value1
    <dbl>   <dbl> <dbl> <chr>    <dbl>   <dbl>  <dbl>
1      33      22  0.02 2233        33      22   0.02
2      33      11  0.03 1133        11      33   0.03
3      33      44  0.03 3344        33      44   0.03
4      22      11  0.03 1122        11      22   0.02
5      22      44  0.01 2244        22      44   0.03
6      11      44  0.01 1144        11      44   0.03

完全匹配您想要的输出:

left_join(tree.dat1, tree.dat2, by = "TreeID") %>% select(-tree1.y, -tree2.y, -TreeID) %>% 
  rename(tree1 = tree1.x, tree2 = tree2.x)

  tree1 tree2 value value1
  <dbl> <dbl> <dbl>  <dbl>
1    33    22  0.02   0.02
2    33    11  0.03   0.03
3    33    44  0.03   0.03
4    22    11  0.03   0.02
5    22    44  0.01   0.03
6    11    44  0.01   0.03

【讨论】:

  • 非常感谢,它不仅适用于我的这部分工作,也是在绘图中使用数据的绝佳解决方案!
【解决方案2】:

这是一个基本的 R 解决方案。因素可能会使您的问题复杂化。如果您必须使用它们,可以在您的项目中转换为字符。

tree.dat1 = data.frame(tree1 = (c(rep(33,3),rep(22,2),11)),
                       tree2 = (c(22,11,44,11,44,44)),
                       value = c(0.02, rep(0.03,3), rep(0.01,2)))

tree.dat2 = data.frame(tree1 = (c(rep(11,3),rep(33,2),22)),
                        tree2 = (c(22,33,44,22,44,44)),
                        value1 = c(rep(3,0.05),0.02,rep(0.03,2)))

tree.dat1$id=apply(tree.dat1[,1:2], 1, function(x)paste(sort(x), collapse="-"))
tree.dat2$id=apply(tree.dat2[,1:2], 1, function(x)paste(sort(x), collapse="-"))

tree.dat3 = left_join(tree.dat1,tree.dat2[,3:4], by = "id")[,-4]


> tree.dat3
  tree1 tree2 value value1
1    33    22  0.02   0.02
2    33    11  0.03   0.03
3    33    44  0.03   0.03
4    22    11  0.03   0.02
5    22    44  0.01   0.03
6    11    44  0.01   0.03

【讨论】:

  • 感谢 R 基础解决方案。很有用。
猜你喜欢
  • 2020-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-03
相关资源
最近更新 更多