如何在保留其他列和 NA 值的同时合并 R 中同一患者 ID# 的行条目?

How do I combine row entries for the same patient ID# in R while keeping other columns and NA values?

我需要为这些多个 ID 组合一些列,并且可以只使用第一个 ID 列表中的值为其他列。例如,在这里我只想结合 "spending" 列和心脏病发作列来说明他们是否曾经心脏病发作。然后我想删除重复的 ID#s,只保留其他列的第一个列表中的值:

df <- read.table(text = 
              "ID  Age   Gender  heartattack    spending 
               1 24 f 0 140
               2 24 m na 123
               2 24 m 1 58
               2 24 m 0 na
               3 85 f 1 170
               4 45 m na 204", header=TRUE)

我需要的:

df2 <- read.table(text = 
            "ID  Age   Gender  ever_heartattack all_spending 
             1 24 f 0 140
             2 24 m 1 181
             3 85 f 1 170
             4 45 m na 204", header=TRUE)

我尝试 group_by 使用 transmute() 和 sum() 如下:

df$heartattack = as.numeric(as.character(df$heartattack))
df$spending  = as.numeric(as.character(df$spending))

library(dplyr)
df = df %>% group_by(ID) %>% transmute(ever_heartattack = sum(heartattack, na.rm = T), all_spending = sum(spending, na.rm=T))

但这会删除所有其他列!它还将 NA 值变为零...例如,我仍然希望 "NA" 成为患者 ID#4 的值,我不想更改数据以表明他们从未心脏病发作!

> print(dfa) #This doesn't at all match df2 :(
  ID ever_heartattack all_spending
1  1                0          140
2  2                1          181
3  2                1          181
4  2                1          181
5  3                1          170
6  4                0          204

你能做到吗?

aggregate(
    spending ~ ID + Age + Gender, 
    data = transform(df, spending = as.numeric(as.character(spending))),
    FUN = sum)
#  ID Age Gender spending
#1  1  24      f      140
#2  3  85      f      170
#3  2  24      m      181
#4  4  45      m      204

一些评论:

  1. 问题是,在聚合时,您没有给出明确的规则来处理不同的其他列中的数据(如本例中的 heartattack)。例如,对于ID = 2为什么保留heartattack = 1而不是heartattack = naheartattack = 0

  2. 你的 "na" 实际上不是真实的 NA。这导致 spending 成为 factor 列而不是 numeric 列向量。


完全重现您可以做到的预期输出

df %>%
    mutate(
        heartattack = as.numeric(as.character(heartattack)),
        spending = as.numeric(as.character(spending))) %>%
    group_by(ID, Age, Gender) %>%
    summarise(
        heartattack = ifelse(
            any(heartattack %in% c(0, 1)),
            max(heartattack, na.rm = T),
            NA),
        spending = sum(spending, na.rm = T))
## A tibble: 4 x 5
## Groups:   ID, Age [?]
#     ID   Age Gender heartattack spending
#  <int> <int> <fct>        <dbl>    <dbl>
#1     1    24 f                0      140
#2     2    24 m                1      181
#3     3    85 f                1      170
#4     4    45 m               NA      204

感觉有点 "hacky" 因为规则不清楚要保留哪个 heartattack 值。在这种情况下,我们

  • 如果 heartattack 包含 0 或 1,则保留 heartattack 的最大值。
  • return NA 如果 heartattack 不包含 0 或 1。