我是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。
答案 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