从数据框获取值到另一个

时间:2011-05-23 13:27:46

标签: r dataframe

我是R编程的新手,刚刚开始学习它,我需要你帮我解决这个问题。

我有2个数据框:

the first(df1):

    V1 V2
    A  A 
    A  B 
    A  C 
    B  A 
    B  B 
    B  C 

etc

第二个(df2):

V1  Va   Vb
A   12   23
B   15   53
C   321  543
D   54   325
etc..

使用此代码生成样本数据。

df1 <- data.frame(
  V1 = rep(LETTERS[1:2], each = 3L),
  V2 = rep.int(LETTERS[1:3], 2L)
)
dfr2 <- data.frame(
  Va = c(12, 15, 312, 54),
  Vb = c(23, 53, 543, 325)
)

我需要从df2获取Va和Vb,并根据df1的V1和V2将它们放在df1中。

所以我想要这个输出:

DF3:

V1   V2  Va1  Vb1 Va2 Vb2
A    A   12    23  12  23
A    B   12    23  15  23
A    C   12    23  321 543
B    A   15    23  12   23
B    B   15    23  15   23
B    C   15    23  321  543

希望这可以在R中完成而不需要几十个for循环:S。

3 个答案:

答案 0 :(得分:4)

您可以使用merge()两次来获得所需内容。默认情况下,merge会查找要加入的常用列名。在第二次合并中,我们将指定要合并的列:

df1 <- data.frame(V1 = c('A', 'A', 'A', 'B', 'B', 'B'), V2 = c('A', 'B', 'C', 'A', 'B', 'C'))
df2 <- data.frame(V1 = c('A', 'B', 'C', 'D'), Va = c(12, 15, 321, 54), Vb = c(23, 53, 543, 325))

merge(merge(df1, df2), df2, by.x = "V2", by.y = "V1", suffixes = c("1", "2"))

答案 1 :(得分:1)

如果df1 $ V1中的名称是唯一的,您可以使用match()的强大功能:

#some data
df1 <- data.frame(
  V1 = rep(c("A","B"),each=3),
  V2 = rep(LETTERS[1:3],2)  
)
df2 <- data.frame(V1=LETTERS[1:3],Va=1:3,Vb=3:1)

out <- cbind(df1,
  df2[match(df1$V1,df2$V1),-1],
  df2[match(df1$V2,df2$V1),-1]
)
names(out)[3:6] <- c("Va1","Vb1","Va2","Vb2")
rownames(out) <- 1:nrow(out)

给出

> out
    V1 V2 Va1 Vb1 Va2 Vb2
1    A  A   1   3   1   3
2    A  B   1   3   2   2
3    A  C   1   3   3   1
4    B  A   2   2   1   3
5    B  B   2   2   2   2
6    B  C   2   2   3   1

您必须手动重命名列,因为您将获得多个具有相同名称的列。尽管在数据框架中技术上是可行的,但它可能会在以后引起麻烦。您可以使用以下内容自动化:

names(out) <- 
    c("V1","V2",
      sapply(names(df2)[2:3],paste,1:2,sep="")
    )

编辑:对于大数据帧,转换为矩阵会产生另一个巨大的差异。人们必须注意不同变量的类型的内在变化。加速是由于cbind和merge需要花费大量时间来确定每个变量的正确类型。

使用以下数据和功能:

n <- 1e5
df1 <- data.frame(V1 = rep(LETTERS,each=n),V2 = rep(LETTERS,n),
        stringsAsFactors=FALSE)
df2 <- data.frame(V1=LETTERS,Va=1:26,Vb=26:1,stringsAsFactors=FALSE)

fast_JM <- function(df1,df2){
  out <- cbind(
    as.matrix(df2[,-1])[match(df1$V1,df2$V1),],
    as.matrix(df2[,-1])[match(df1$V2,df2$V1),]
  )
  out <- as.data.frame(out)
  names(out) <- sapply(names(df2)[2:3],paste,1:2,sep="")
  out$V1 <- df1$V1
  out$V2 <- df1$V2
  out
}

slow_JM <- function(df1,df2){
  out <- cbind(df1,
    df2[match(df1$V1,df2$V1),-1],
    df2[match(df1$V2,df2$V1),-1]
  )
  names(out)[3:6] <- c("Va1","Vb1","Va2","Vb2")
  out
}


double_merge <- function(df1,df2){
  merge(merge(df1, df2), df2, by.x = "V2", by.y = "V1", suffixes = c("1", "2"))

}

基准测试成为:

require(rbenchmark)
benchmark(fast_JM(df1,df2),slow_JM(df1,df2),double_merge(df1,df2),
      replications=1,columns=c("test","elapsed","relative"),order="relative")

                    test elapsed relative
1      fast_JM(df1, df2)    0.89  1.00000
2      slow_JM(df1, df2)   12.54 14.08989
3 double_merge(df1, df2)   42.50 47.75281

与双合并相比,加速速度提高了40倍以上,与使用数据帧相比提升了10倍以上。

答案 2 :(得分:1)

我认为Hadley Wickham的dplyr软件包有一些很好的工具来组合数据帧。到达同一个地方的方式不同。

df1 <- data.frame(
  V1 = rep(LETTERS[1:2], each = 3L),
  V2 = rep.int(LETTERS[1:3], 2L)
)
dfr2 <- data.frame(
  V1 = LETTERS[1:4],
  Va = c(12, 15, 312, 54),
  Vb = c(23, 53, 543, 325)
)

##necessary libraries
library(magrittr, dplyr)

现在,使用left_join()包中的rename()dplyr函数以及magrittr包中的管道运算符,我认为您可以节省大量的击键次数

df3 <- df1 %>% #pipe operator (%>%) is from magrittr package
  dplyr::left_join(dfr2, c('V1'="V1")) %>% #merge once
  dplyr::rename(Va1 = Va, Vb1 = Vb) %>%  #rename columns
  dplyr::left_join(dfr2, c('V2'="V1")) %>% #merge on different column
  dplyr::rename(Va2 = Va, Vb2 = Vb) #rename again

这也可以通过一次合并而不是两次合并完成,但我喜欢看看每一步中发生了什么。

> print(df3)
  V1 V2 Va1 Vb1 Va2 Vb2
1  A  A  12  23  12  23
2  A  B  12  23  15  53
3  A  C  12  23 312 543
4  B  A  15  53  12  23
5  B  B  15  53  15  53
6  B  C  15  53 312 543