在 R 中,有条件地在另一个数据框中查找变量

In R, conditionally look up a variable in another dataframe

背景

我在 r 中有两个 df,一个叫 d,另一个叫 insuranced 包含唯一 ID 的列表以及两个属性 genderzip(与 this 问题无关)。 insurance 包含一些相同的 ID 数字,但它们不是唯一的。它们代表了特定年份的人们的健康保险计划。 insurance table 中的一些 ID 重复,因为那个人在那一年有不止一个保险计划(即他们更换了保险公司)。下面是制作这些 table 的一些代码:

d <- data.frame(ID = c("a","b","c","d","e","f"), 
                    gender = c("f","f","m","f","m","m"), 
                    zip = c(48601,60107,29910,54220,28173,44663),stringsAsFactors=FALSE)

看起来像:

ID gender zip
a f 48601
b f 60107
c m 29910
d f 54220
e m 28173
f m 44663
insurance <- data.frame(ID = c("a","a","c","d","f","f"), 
                     ins_type = c("public","private","private","private","private","public"), 
                     insurer = c("medicare","aetna","cigna","uhc","uhc","medicaid"),
                     stringsAsFactors = FALSE)

看起来像:

ID ins_type insurer
a public medicare
a private aetna
c private cigna
d private uhc
f private uhc
f public medicaid

这是我的目标:

我需要 d 来反映 d$ID 中是否有人拥有任何 public 保险,如果有,是哪家保险公司。具体来说,这意味着“查找”insurance table 并在 d 中创建 2 个新变量:首先,一个 1/0 或 yes/no 变量永远具有 public保险(称这个变量为d$public);第二,它是哪家保险公司(称之为d$insurer)。

棘手的一点是我需要 d$ID 来保持唯一性,因为它必须是我未在此处概述的项目的另一个方面的主键。所以这个想法是,如果任何 IDany 条目用于 public 保险,那么 d$public 应该得到“1”或“是”或随便。

想要的结果

我想要一个看起来像这样的 table:

ID gender zip public insurer
a f 48601 1 medicare
b f 60107 0 NA
c m 29910 0 NA
d f 54220 0 NA
e m 28173 0 NA
f m 44663 1 medicaid

我试过的

此问题的多个版本之前已被问到(例如 , here),但我不太答对。

我试过使用连接,像这样:

d2 <- d %>%
  left_join(insurance, by=c("ID"="ID"))

这为我提供了我想要的列,但它使像 a 这样的 ID 重复,这是我不能拥有的。

感谢您的帮助!


d %>% 
      left_join(insurance %>% filter(ins_type == "public"), by = "ID") %>%
      mutate(public = ! is.na(ins_type)) %>%
      select(-ins_type)

这是一个使用 base R 的解决方案。无需安装任何与 tidyverse 相关的包。

# Define public column based on insurance$ins_type
df$public <- ifelse(insurance$ins_type == "public", 1, 0)

# Now we'll define df$insurer as the result of applying a function
# that receives the ids and df$public as arguments.

# if the public type is not 1, return NA, else return the insurer name
# in the insurance df where type is 1 and id = id

df$insurer <- mapply(
    function(id, type) {
    if(type != 1)
        return(NA)
    return(insurance$insurer[insurance$id == id & insurance$type == type])
    }
    df$id,
    df$public
)