从重复表创建id变量

时间:2018-03-01 16:24:35

标签: r data-manipulation

我有一个数据框,其中每一行都有唯一的标识符,但有些行实际上是重复的。

fdf <- data.frame(name = c("fred", "ferd", "frad", 'eric', "eirc", "george"),
                  id = 1:6)
fdf
#>     name id
#> 1   fred  1
#> 2   ferd  2
#> 3   frad  3
#> 4   eric  4
#> 5   eirc  5
#> 6 george  6

我已确定哪些行是重复的,并且此信息作为唯一ID的对存储在第二个数据帧中。因此,密钥告诉我第1行与第2行和第3行是同一个人,等等。

key <- data.frame(id1 = c(1,1,2,4), id2 = c(2,3,3,5))
key
#>   id1 id2
#> 1   1   2
#> 2   1   3
#> 3   2   3
#> 4   4   5

我正在努力想出一种直接的方法来使用密钥在我的原始数据帧中创建一个id变量。期望的输出将是:

fdf$realid <- c(1,1,1,2,2,3)
fdf
#>     name id realid
#> 1   fred  1      1
#> 2   ferd  2      1
#> 3   frad  3      1
#> 4   eric  4      2
#> 5   eirc  5      2
#> 6 george  6      3

为了清晰起见而编辑

这里的键是data.frame fdf中行之间的真实连接集。因此,您可以想象从所有可行连接的集合开始:

#  id1 id2
#   1   2
#   1   3
#   1   4
#   ...
#   6   4
#   6   5

确定哪些是真实的连接(基于每个观察中的其他变量)。

#  id1 id2 match
#   1   2   match
#   1   3  no match
#   1   4   match
#   ...
#   6   4   no match
#   6   5   no match

并将子设置为匹配的案例。

3 个答案:

答案 0 :(得分:2)

最简单的方法是将 key 数据框重新创建为以下格式(即哪个id属于哪个idid)

key <- data.frame(id     = c(1, 2, 3, 4, 5, 6), 
                  realid = c(1, 1, 1, 2, 2, 3))

然后只需将 fdf merge

合并在一起
fdf <- merge(fdf, key_table, by.x = "id")
fdf
  id   name realid
1  1   fred      1
2  2   ferd      1
3  3   frad      1
4  4   eric      2
5  5   eirc      2
6  6 george      3

答案 1 :(得分:1)

我没有找到一种直接的方式,但似乎运作良好。

首先检查组中的ID是否在一起,检查是否存在“重叠”,即key中两行之间的交集是否为非空:< / p>

check_overlap <- function(pair1, pair2){
  newset <- intersect(pair1, pair2)
  length(newset) != 0
}

然后我们可以将此函数应用于key中与其他行相对的行。如果已经匹配了某行,则会自动从key中删除,如下所示:

check_overlaps <- function(key){
  cont <- data.frame()
  i <- 1
  while(nrow(key) > 0){
    ids  <- apply(key, 1, check_overlap, key[1, ])
    vals <- unique(unlist(key[ids, ]))
    key  <- key[!ids, ]
    cont <- rbind(cont, cbind(vals, rep(i, length(vals))))
    i <- i+1
  }
  return(cont)
}

new_ids <- check_overlaps(key)
#    vals V2
# 1    1  1
# 2    2  1
# 3    3  1
# 4    4  2
# 5    5  2

合并fdfnew_ids的问题是,key中可能不会出现一些旧ID,但应根据新订单将其映射到新ID 。您可以先验地操纵key并执行:

for(val in unique(fdf$id)){
  if(!(val %in% unlist(key))){
    key <- rbind(key, c(val, val))
  }
}

new_ids2 <- check_overlaps(key)
     vals V2
# 1    1  1
# 2    2  1
# 3    3  1
# 4    4  2
# 5    5  2
# 6    6  3

很容易与fdf合并,如:

merge(fdf, new_ids2, by.x = "id", by.y = "vals")
    id   name V2
# 1  1   fred  1
# 2  2   ferd  1
# 3  3   frad  1
# 4  4   eric  2
# 5  5   eirc  2
# 6  6 george  3

答案 2 :(得分:1)

如果我正确理解了您的问题,可以通过创建匹配ID组并从这些组中创建新(真实)ID来解决:

# determine the groups of ids
id_groups <- list()
i = 1
for (id in unique(key$id1)) {
  if (!(id %in% unlist(id_groups))) {
    id_groups[[i]] <- c(id, key$id2[key$id1 == id])
    i = i + 1
  }
}

# add ids without match
id_groups <- c(id_groups, setdiff(fdf$id, unlist(id_groups)))

# for every id in fdf, set real_id to index in id_groups to which id belongs
fdf$real_id <- sapply(fdf$id, function(id) {
  which(sapply(id_groups, function(group) id %in% group))
})