匹配数据框列:一个是int,另一个是列表

时间:2017-09-05 17:48:31

标签: r dataframe match

尝试根据另一个数据帧df2中的匹配在数据帧df1中创建一个列,其中df1远大于df2:

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

这不太有用,因为df2 $ IDs列是一个列表:

> 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)。对于所有其他行,'match(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 个答案:

答案 0 :(得分: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

Fyi,match方法不会自然地扩展到加入更多列,因此您可能希望最终学习data.table及其更新连接&#34;这种情况的语法:

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 ]