【问题标题】:Loop over multiple columns in a merge in R在R中的合并中循环多个列
【发布时间】:2015-08-18 23:20:12
【问题描述】:

我正在尝试循环合并多个列上的两个数据帧,但我遇到了代码问题,并且无法在 SO 上找到任何答案。以下是一些示例数据框:

box <- c(5,7,2)
year <- c(1999,1999,1999)
rep5 <- c(5,5,5)
rep7 <- c(7,7,7)
rep2 <- c(2,2,2)
df1 <- data.frame(box,year,rep5,rep7,rep2)

box1 <- c(5,5,5,5,7,7,7,7,2,2,2,2)
box2 <- c(5,7,2,5,5,7,2,4,5,7,2,9)
year2 <- c(1999,1999,1999,2000,1999,1999,1999,1999,1999,1999,1999,1999)
distance <- c(0,100,200,0,100,0,300,200,200,300,0,300)
df2 <- data.frame(box1,box2,year2,distance)

df1
  box year rep5 rep7 rep2
1   5 1999    5    7    2
2   7 1999    5    7    2
3   2 1999    5    7    2

df2
   box1 box2 year2 distance
1     5    5  1999        0
2     5    7  1999      100
3     5    2  1999      200
4     5    5  2000        0
5     7    5  1999      100
6     7    7  1999        0
7     7    2  1999      300
8     7    4  1999      200
9     2    5  1999      200
10    2    7  1999      300
11    2    2  1999        0
12    2    9  1999      300

我要做的是获取从 df2 到 df1 的距离信息,其中 df1 year 与 df2 year 匹配,df1 box 与 df2 box1 匹配,df1 rep[i] 与 df2 box2 匹配。我可以为单个 df1 rep[i] 列执行此操作,如下所示:

merge(df1, df2, by.x=c("box", "rep5", "year"), by.y=c("box1", "box2", "year2"), all.x = TRUE)

这给出了所需的输出:

  box rep5 year rep7 rep2 distance
1   2    5 1999    7    2      200
2   5    5 1999    7    2        0
3   7    5 1999    7    2      100

但是,为了单独为每个 rep[i] 列保存此操作(我在真实数据集中有很多这些列),我希望能够遍历这些列。这是我尝试这样做的代码:

reps <- c(df1$rep7, df1$rep2)
df3 <- for (i in reps) {merge(df1, df2, by.x=c("box", i, "year"), by.y=c("box1", "box2", "year2"), all.x = TRUE)}
df3

当我运行该代码时,我收到错误“fix.by(by.x, x) 中的错误:'by' 必须指定唯一有效的列。”我也尝试定义

reps <- c("rep7", "rep2")

当我使用该定义运行相同的代码时,我得到 df3 为 NULL 的结果。

我想要的输出(为清楚起见重命名了距离列)是:

  box year rep5 rep7 rep2 dist5 dist7 dist2
1   2 1999    5    7    2   200   300     0
2   5 1999    5    7    2     0   100   200
3   7 1999    5    7    2   100     0   300

我做错了什么?非常感谢您能给我的任何帮助!

【问题讨论】:

    标签: r for-loop merge


    【解决方案1】:

    当我了解库 dplyrtidyr 以及 concept of tidy data sets 后,我的 R 生活变得轻松多了。您在上面尝试执行的操作可以表示为pivot,并且使用dplyrtidyr 很容易做到。

    我假设你真正想要的是转 df2:

       box1 box2 year2 distance
    1     5    5  1999        0
    2     5    7  1999      100
    3     5    2  1999      200
    4     5    5  2000        0
    5     7    5  1999      100
    6     7    7  1999        0
    7     7    2  1999      300
    8     7    4  1999      200
    9     2    5  1999      200
    10    2    7  1999      300
    11    2    2  1999        0
    12    2    9  1999      300
    

    进入您的输出,删除所有那些奇怪的重复:

      box year dist5 dist7 dist2
    1   2 1999   200   300     0
    2   5 1999     0   100   200
    3   7 1999   100     0   300
    

    因此,您应该将box2 旋转到列中,并将您的距离作为值。使用dplyrtidyr

    library(tidyr)
    box1 <- c(5,5,5,5,7,7,7,7,2,2,2,2)
    box2 <- c(5,7,2,5,5,7,2,4,5,7,2,9)
    year2 <- c(1999,1999,1999,2000,1999,1999,1999,1999,1999,1999,1999,1999)
    distance <- c(0,100,200,0,100,0,300,200,200,300,0,300)
    df2 <- data.frame(box1,box2,year2,distance)
    
    # reshape it as desired
    spread(df2, box2, distance,fill=0)
    #Source: local data frame [4 x 7]
    
    #  box1 year2   2   4   5   7   9
    #1    2  1999   0   0 200 300 300
    #2    5  1999 200   0   0 100   0
    #3    5  2000   0   0   0   0   0
    #4    7  1999 300 200 100   0   0
    

    我的建议:学会使用dplyrtidyr。它让生活变得如此轻松。

    【讨论】:

    • 那里根本不需要dplyrspread(data, box2, distance, fill = 0)
    • 不,没有,但他们像 Jack 和 Jill 一样在一起,所以我想我会把他们包括在内,这样他就知道谷歌的内容了。
    • 我是 dplyr 的忠实粉丝,但我 100% 支持 @RichardScriven。这是一个很好的答案,但是使用管道会使以前从未见过它的用户感到恐惧。此外,使用单一功能的管道是完全没有意义的。管道非常适合将嵌套的“由内而外”的东西变成线性的从左到右的东西。当你没有嵌套时,管道只是一种奇怪的习惯。我的建议是保留您对 OP 的建议以查看 dplyr,但不要将 dplyr 知识作为使用答案的先决条件,这样您就可以使用单个 %&gt;%
    • 感谢您的反馈!我是 R 和 Stack Overflow 的新手,所以我很感激这些提示。
    • @emesrever 确定!如果您编辑答案并提供无 dplyr 版本,我什至会给您一个赞成票;)
    猜你喜欢
    • 2016-06-18
    • 2019-03-07
    • 2014-04-19
    • 2021-07-21
    • 1970-01-01
    • 2018-10-27
    • 1970-01-01
    • 2016-08-07
    • 1970-01-01
    相关资源
    最近更新 更多