r中的多个数据帧相对于行或样本的交集

时间:2015-04-06 19:54:00

标签: r dataframe data.table

我有很多帧,其中的一些ID或列名是相同的。我想将所有数据帧合并到一个数据帧中,但仅限于所有数据帧中存在的样本。换句话说,我希望新数据帧中的样本交集。例如,第一个数据框(df1)看起来像

       m1      m2     m3
P001   60.00   2.0     1
P002   14.30   2.077   1
P003   29.60   2.077   1.4
P004   10.30   2.077   1.3
P005   79.30   2.077   3.1
P006   79.30   2.077   3.1
P008    9.16   2.077   2.2

,第二个数据框(df2)看起来像

patid  n1      n2   n3
P001   12.00   2.0   1
P003   17.60   1.7   1
P005   22.30   2.7   1
P006   26.30   1.7   1

同样是第三个数据框

patid  k2      k3   k4
P001   8.00   2.0   1.7
P004   9.60   1.7   1.8
P005   7.30   2.7   2.1
P008   6.30   1.7   1.9
P008   6.38   1.78  1.92

我希望第四个数据帧与该数据帧中的所有样本相交。该数据帧中该数据帧中的样本将用于例如P001和P005。

答案可能是这样的

       m1      m2     m3      n1      n2    n3    k2     k3    k4
P001   60.00   2.0     1      12.00   2.0   1     8.00   2.0   1.7
P005   79.30   2.077   3.1    22.30   2.7   1     7.30   2.7   2.1

更长的选择是使用循环。嵌套匹配,例如

matchmicSer <- df2[match(rownames(df1), df2$patid)]

matchserMic <- df1[match(df2$patid,rownames(df1))]

并继续,但我相信R应该有一个捷径。合并不是一种选择,因为第二和第三个数据帧中的一些变量可能有重复,如thrid数据帧中的P008。

3 个答案:

答案 0 :(得分:4)

根据显示的示例,第一个数据集(&#39; df1&#39;)没有'patid&#39;柱。因此,从&#39; rownames&#39;创建了列。

df1$patid <- row.names(df1)

我们可以在将数据集放入&#39;列表后将Reducemerge一起使用。 (mget(paste0('df', 1:3))

Reduce(function(...) merge(..., by='patid'), mget(paste0('df', 1:3)))
#  patid   m1    m2  m3   n1  n2 n3  k2  k3  k4
#1  P001 60.0 2.000 1.0 12.0 2.0  1 8.0 2.0 1.7
#2  P005 79.3 2.077 3.1 22.3 2.7  1 7.3 2.7 2.1

更新

关于重复的patid,在&#39; df3&#39;中,有一个副本(&#39; P008&#39;),但它并不存在于所有数据集中(所以没有在输出中找到)。假设,如果我们有一个&#39; patid&#39;它存在于所有数据集中,并在其中一个数据集中重复

 df3$patid[2] <- 'P001'
 Reduce(function(...) merge(..., by='patid'), mget(paste0('df', 1:3)))
 #  patid   m1    m2  m3   n1  n2 n3  k2  k3  k4
 #1  P001 60.0 2.000 1.0 12.0 2.0  1 8.0 2.0 1.7
 #2  P001 60.0 2.000 1.0 12.0 2.0  1 9.6 1.7 1.8
 #3  P005 79.3 2.077 3.1 22.3 2.7  1 7.3 2.7 2.1

数据

 df1 <- structure(list(m1 = c(60, 14.3, 29.6, 10.3, 79.3, 79.3, 9.16), 
 m2 = c(2, 2.077, 2.077, 2.077, 2.077, 2.077, 2.077), m3 = c(1, 
 1, 1.4, 1.3, 3.1, 3.1, 2.2)), .Names = c("m1", "m2", "m3"
 ), class = "data.frame", row.names = c("P001", "P002", "P003", 
 "P004", "P005", "P006", "P008"))

df2 <-  structure(list(patid = c("P001", "P003", "P005", "P006"),
 n1 = c(12, 17.6, 22.3, 26.3), n2 = c(2, 1.7, 2.7, 1.7), n3 = c(1L,
1L, 1L, 1L)), .Names = c("patid", "n1", "n2", "n3"),
 class = "data.frame", row.names = c(NA, -4L))

df3 <- structure(list(patid = c("P001", "P004", "P005", "P008",
 "P008"), k2 = c(8, 9.6, 7.3, 6.3, 6.38), k3 = c(2, 1.7, 2.7, 1.7,
 1.78), k4 = c(1.7, 1.8, 2.1, 1.9, 1.92)), .Names = c("patid", "k2", 
 "k3", "k4"), class = "data.frame", row.names = c(NA, -5L))

答案 1 :(得分:2)

我已经开始执行批量加入的功能来解决您的问题。
使用akrun生成的数据:

library(data.table) # devtools::install_github("Rdatatable/data.table")
dt1 <- as.data.table(df1, keep.rownames = "patid")
dt2 <- as.data.table(df2)
dt3 <- as.data.table(df3)

library(dwtools) # devtools::install_github("jangorecki/dwtools")
joinbyv(dt3, list(dt2, dt1), by = list("patid","patid"), nomatch = list(0L,0L))
#    patid   m1    m2  m3   n1  n2 n3  k2  k3  k4
# 1:  P001 60.0 2.000 1.0 12.0 2.0  1 8.0 2.0 1.7
# 2:  P005 79.3 2.077 3.1 22.3 2.7  1 7.3 2.7 2.1

当然,如果您不想在代码中使用新的依赖项(dwtools),则可以将简单joinbyv函数定义为:

joinbyv <- function(master, join, by, nomatch){
    joinby <- function(master, join, by, nomatch){
        setkeyv(join,by)
        if(!identical(key(master),key(join))) setkeyv(master,key(join))
        join[master, nomatch = nomatch]
    }
    for(i in 1:length(join)){
        master <- joinby(master = master, join[[i]], by[[i]], nomatch[[i]])
    }
    master
}

答案 2 :(得分:0)

我假设您希望保留在某些表格中重复的共享ID的所有观察结果。

我写在data.table

library(data.table) #1.9.5+
setDT(df1,keep.rownames="patid",key="patid")
setDT(df2,key="patid")
setDT(df3,key="patid")

df4<-df1[df2][df3,nomatch=0L]