2017-09-05 101 views
1

试图基于匹配的另一个数据帧DF2,其中DF1比DF2更大的创造数据帧DF1列:匹配数据帧列:一个int和另一个是列表

df1$val2 <- df2$val2[match(df1$id, df2$IDs)] 

这完全不是那么回事因为DF2 $标识列的列表:

> df2 
      IDs val2 
1    0 1 
2   1, 2 2 
3   3, 4 3 
4   5, 6 4 
5   7, 8 5 
6   9, 10 6 
7 11, 12, 13, 14 7 

它仅适用于在列表中有1元的部分(第1行:.. $:以上INT 0)。对于所有其他行,'匹配(df1 $ id,df2 $ IDs)'返回NA。

匹配一些个体数量的测试工作得很好用双括号:

2 %in% df2[[2,'IDs']] 

所以,我要么需要修改列DF2 $ ID或需要以不同的方式进行匹配操作。 df1有许多其他列,df2也是如此,但df2在行中要短得多。

的情况下,可以用下面的被复制:

IDs <- c("[0]", "[1, 2]", "[3, 4]", "[5, 6]", "[7, 8]", "[9, 10]", "[11, 12, 13, 14]") 
val2 <- c(1,2,3,4,5,6,7) 
df2 <- data.frame(IDs, val2) 
df2$IDs <- lapply(strsplit(as.character(df2$IDs), ','), function (x) as.integer(gsub("\\s|\\[|\\]", "", x))) 
id <- floor(runif(100, min=0, max=15)) 
df1 <- data.frame(id) 
str(df1) 
str(df2) 
df1$val2 <- df2$val2[match(df1$id, df2$IDs)] 
+1

一可重复的例子可以来得心应手...你有没有尝试unlist(df2 $ ID)? – Cris

+0

@Cris。谢谢。这将产生一个平面列表,但我们需要保持每行适当的列表。例如,在第2行中,我们列出了:int 1 2.这告诉我们所有具有值1和2的ID映射到该行。 – Dimon

+0

您正在讨论一个示例,但这不同于构建和提供*可重现*示例。请参阅https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/28481250#28481250 – Frank

回答

2

名单列笨拙的工作。如果转换df2一个更香草格式,它的工作原理:

DF2 = with(df2, data.frame(ID = unlist(IDs), val2 = rep(val2, lengths(IDs)))) 
df1$m = DF2$val2[ match(df1$id, DF2$ID) ] 

如果你想只为浏览列表列,它是快速做......

aggregate(ID ~ ., DF2, list) 

    val2    ID 
1 1    0 
2 2   1, 2 
3 3   3, 4 
4 4   5, 6 
5 5   7, 8 
6 6   9, 10 
7 7 11, 12, 13, 14 


据透露,该match做法自然不会扩展到加入更多的列,因此您可能希望最终学会data.table和它的“更新加入”语法这种情况:

library(data.table) 
setDT(df1); setDT(df2) 

DT2 = df2[, .(ID = unlist(IDs)), by=setdiff(names(df2), "IDs")] 
df1[DT2, on=.(id = ID), v := i.val2 ] 
+1

谢谢。这工作。我想的另一种方法是通过字符串匹配(即保持原始ID为字符串)。我没有得到它的工作。此外,它可能比你的版本慢,但是,更通用的版本。 – Dimon

相关问题