首页 > 解决方案 > 在 R 中创建匹配对

问题描述

我有一个约 20,000 个案例的数据集,每个案例有 3 个可能的控件。每个案例和控制都由一个 ID 变量唯一标识。可能的控件有一些重叠,因为它们以不允许在没有替换的情况下匹配的方式与 SQL 中的案例连接。我已将数据导入 R 并将其视为一组约 20,000 个病例和约 50,000 个对照,以便为与数据集中的协变量(例如年龄)匹配的每个病例仅选择一个对照。我想要的输出是第 1 列中的案例 ID 和第 2 列中的匹配控制 ID。

我一直在尝试使用 MatchIt 包进行匹配,但包 (match.matrix) 的输出是与案例或控件不明确对应的 ID 列表。该包有一个名为 get_matches 的函数,看起来它会返回适当的输出,但函数参数对我来说是不透明的——我不知道是id_cols什么getdata。似乎没有任何关于如何使用 MatchIt(或其他包)的教程来仅返回带有匹配控件 ID 的案例 ID 列表。我正在使用马氏距离,但不关心实际距离测量或返回倾向得分。什么是最好的包和方法来选择最匹配每个案例的单个控件,而不需要替换,

导入数据示例(注意一些可能的匹配项之间的重叠):

case_ID <- c(1,1,1,2,2,2,3,3,3,4,4,4)
control_ID <- c(5,6,7,8,9,10,5,6,7,11,12,13)
age <- c(12,12,12,56,56,56,12,12,12,62,62,62)
score <- c(7,7,7,3,3,3,7,7,7,9,9,9)
parity <- c(1,1,1,4,4,4,1,1,1,2,2,2)
retested <- c(1,1,1,0,0,0,1,1,1,1,1,1)

df <- cbind(case_ID, control_ID, age, score, parity, retested)

期望的输出(显示协变量):

matched_case <- c(1,2,3,4)
matched_control <- c(5,8,6,11)
matched_age <- c(12,56,12,62)
matched_score <- c(7,3,7,9)
matched_parity <- c(1,4,1,2)
matched_retested <- c(1,0,1,1)

matched_df <- cbind(matched_case, matched_control, matched_age, matched_score, matched_parity, matched_retested)

标签: rmatching

解决方案


我不是 100% 确定,但此代码至少适用于您的示例。从您的评论中,我得出结论,样本并不能说明全部情况。它也会很慢。但这可能是一个开始。

case_ID     <- c( 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4)
control_ID  <- c( 5, 6, 7, 8, 9,10, 5, 6, 7,11,12,13)
age         <- c(12,12,12,56,56,56,12,12,12,62,62,62)
score       <- c( 7, 7, 7, 3, 3, 3, 7, 7, 7, 9, 9, 9)
parity      <- c( 1, 1, 1, 4, 4, 4, 1, 1, 1, 2, 2, 2)
retested    <- c( 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1)

df <- data.frame(case_ID, control_ID, age, score, parity, retested)

df$unq <- apply(df[, 2:6], 1, paste, collapse = "")
r <- 1
#discarded <- character()
while (r < nrow(df)) {
  # find all discarded and remove
  discarded <- c(df[r, "unq"]) # accept current `r` but discard the coming ones
  discarded <- which(df$unq[(r+1):length(df)] == discarded)
  if(length(discarded) > 0) {
    discarded <- discarded + r
    df <- df[-discarded, ]
  }
  # Find further instances of this case and remove
  discarded <- c(df[r, "case_ID"])
  discarded <- which(df$case_ID[(r+1):length(df)] == discarded)
  if(length(discarded) > 0) {
    discarded <- discarded + r
    df <- df[-discarded, ]
  }
  # Next!
  r <- r+1
}

推荐阅读