2013-07-26 32 views
35

我想合并两个数据帧,保持其中一个数据帧的原始行顺序(在下例中为df.2)。在保持原始行顺序的情况下合并两个数据帧

下面是一些示例数据(从class列中的所有的值在两个数据帧定义):

df.1 <- data.frame(class=c(1,2,3), prob=c(0.5,0.7,0.3)) 
df.2 <- data.frame(object=c('A','B','D','F','C'), class=c(2,1,2,3,1)) 

如果我:

merge(df.2,df.1) 

结果是:

class object prob 
1  1  B 0.5 
2  1  C 0.5 
3  2  A 0.7 
4  2  D 0.7 
5  3  F 0.3 

如果我加sort=FALSE

merge(df.2,df.1, sort=F)               

结果是:

class object prob 
1  2  A 0.7 
2  2  D 0.7 
3  1  B 0.5 
4  1  C 0.5 
5  3  F 0.3 

我想的是:

class object prob 
1  2  A 0.7 
2  1  B 0.5 
3  2  D 0.7 
4  3  F 0.3  
5  1  C 0.5 
+0

问题没有明确定义。如果你在合并结果中有比df.2更多或更少的行呢? – agstudy

+0

不可能,因为我使用df.2作为合并函数中的第一个变量... – DJack

+0

不是。仍然不好定义。例如:df.2 <-data.frame(object = c('A','B','D','d' 'F','C'),class = c(2,1,2,4,1))' – agstudy

回答

21

查看plyr包中的连接函数。这就像合并,但它可以让你保持其中一个数据集的行顺序。总的来说,它比合并更灵活。

使用您的数据。例如,我们可以使用join这样的:

> join(df.2,df.1) 
Joining by: class 
    object class prob 
1  A  2 0.7 
2  B  1 0.5 
3  D  2 0.7 
4  F  3 0.3 
5  C  1 0.5 

这里有一对夫妇的描述修复的合并功能以保持行顺序链接:

http://www.r-statistics.com/2012/01/merging-two-data-frame-objects-while-preserving-the-rows-order/

http://r.789695.n4.nabble.com/patching-merge-to-allow-the-user-to-keep-the-order-of-one-of-the-two-data-frame-objects-merged-td4296561.html

+0

在这里显示解决方案,不要只引用它们。链接可以在互联网上相当快速地失效.. – stefan

+0

这些链接中的每一个都深入讨论了合并函数的问题,因此我将它们作为链接保留。 (但是我会再次在plyr包中加入一个连接函数的插件。) – user2635373

+2

我(和'join'文档)不同意它比'merge'更“灵活”:“连接通常比合并,尽管它的功能稍差 - 它目前没有办法重新命名输出或合并x和y数据帧中的不同变量。“ – joran

38

你只需要创建一个变量,其给出了df.2的行号。然后,一旦合并了数据,就会根据此变量对新数据集进行排序。下面是一个例子:

df.1<-data.frame(class=c(1,2,3), prob=c(0.5,0.7,0.3)) 
df.2<-data.frame(object=c('A','B','D','F','C'), class=c(2,1,2,3,1)) 
df.2$id <- 1:nrow(df.2) 
out <- merge(df.2,df.1, by = "class") 
out[order(out$id), ] 
1

感谢@PAC,我想出了这样的事情:

merge_sameord = function(x, y, ...) { 
    UseMethod('merge_sameord') 
} 

merge_sameord.data.frame = function(x, y, ...) { 
    rstr = paste(sample(c(0:9, letters, LETTERS), 12, replace=TRUE), collapse='') 
    x[, rstr] = 1:nrow(x) 
    res = merge(x, y, all.x=TRUE, sort=FALSE, ...) 
    res = res[order(res[, rstr]), ] 
    res[, rstr] = NULL 
    res 
} 

这假设您要保留第一个数据帧的顺序,并且合并的数据帧将具有与第一个数据帧相同的行数。它将为您提供干净的数据框,无需额外的列。

5

您还可以查看Hadley的dplyr软件包中的inner_join函数(下一次迭代plyr)。它保留了第一个数据集的行顺序。您希望的解决方案的细微差别在于它还保留了第一个数据集的原始列顺序。所以它不一定会把我们用于合并的列放在第一个位置。

使用你上面的例子中,inner_join结果如下:

inner_join(df.2,df.1) 
Joining by: "class" 
    object class prob 
1  A  2 0.7 
2  B  1 0.5 
3  D  2 0.7 
4  F  3 0.3 
5  C  1 0.5 
3

accepted answer提出了手动方式使用merge,其中工程时代最,但需要不必要的人工工作时维持秩序。该解决方案还对How to ddply() without sorting?后面,与维持秩序的问题,而是在拆分申请,结合上下文交易:

这个plyr邮件列表上想出了一段时间后(由@kohske没有提出以下),这是由Peter Meil​​strup为有限的情况下提供了一个解决方案:

#Peter's version used a function gensym to 
# create the col name, but I couldn't track down 
# what package it was in. 
keeping.order <- function(data, fn, ...) { 
    col <- ".sortColumn" 
    data[,col] <- 1:nrow(data) 
    out <- fn(data, ...) 
    if (!col %in% colnames(out)) stop("Ordering column not preserved by function") 
    out <- out[order(out[,col]),] 
    out[,col] <- NULL 
    out 
} 

所以,现在你可以使用这个通用keeping.order功能,以保持一个merge呼叫的原行顺序:

df.1<-data.frame(class=c(1,2,3), prob=c(0.5,0.7,0.3)) 
df.2<-data.frame(object=c('A','B','D','F','C'), class=c(2,1,2,3,1)) 
keeping.order(df.2, merge, y=df.1, by = "class") 

这将产生,如要求:

> keeping.order(df.2, merge, y=df.1, by = "class") 
    class object id prob 
3  2  A 1 0.7 
1  1  B 2 0.5 
4  2  D 3 0.7 
5  3  F 4 0.3 
2  1  C 5 0.5 

所以keeping.order可以有效地自动在接受答案的方法。

0

在基地可能有一个更有效的方法。这将是一个相当简单的功能。

varorder <- names(mydata) # --- Merge 
mydata <- merge(mydata, otherData, by="commonVar") 
restOfvars <- names(mydata[!(names(mydata) %in% varorder)]) 

mydata[c(varorder,restOfvars)] 
9

data.table v1.9.5+,你可以这样做:在df.2df.1找出匹配行的每一行,提取相应的列上class柱联接

require(data.table) # v1.9.5+ 
setDT(df.1)[df.2, on="class"] 

的执行。

2

为了完整起见,在连接中更新的也保留了原始的行顺序。如果只有几列追加这可能是Arun's data.table answer替代:

library(data.table) 
setDT(df.2)[df.1, on = "class", prob := i.prob][] 
object class prob 
1:  A  2 0.7 
2:  B  1 0.5 
3:  D  2 0.7 
4:  F  3 0.3 
5:  C  1 0.5 

这里,df.2是正确连接到df.1并获得其从复制一个新列prob匹配df.1的行。

1

在这种特定的情况下,你可以我们factor用于小型基础的解决方案:

  1. 你必须包含一个查找表:

    df.2$prob = factor(df.2$class,labels=df.1$prob) 
    
    df.2 
    # object class prob 
    # 1  A  2 0.7 
    # 2  B  1 0.5 
    # 3  D  2 0.7 
    # 4  F  3 0.3 
    # 5  C  1 0.5 
    

    没有一个通用的解决方案然而,如果工作唯一值

  2. 要更新表格而不是创建新表格
  3. 查找表由合并列
  4. 查找表没有多余水平
  5. 你想要一个left_join
  6. 如果你罚款的因素

1是不可转让的排序,其余的我们可以这样做:

df.3 <- df.2 # deal with 2. 
df.1b <- df.1[order(df.1$class),] # deal with 3 
df.1b <- df.1b[df.1$class %in% df.2$class,] # deal with 4. 
df.3$prob = factor(df.3$class,labels=df.1b$prob) 
df.3 <- df3[!is.na(df.3$prob),] # deal with 5. if you want an `inner join` 
df.3$prob <- as.numeric(as.character(df.3$prob)) # deal with 6. 
相关问题