我可以使用dplyr mutate()或ifelse语句从诊断变量开始生成条件时间吗?

时间:2016-10-28 23:08:04

标签: r dplyr

我想创建一个“自诊断时间”变量,该变量以我的数据中的其他两个现有变量为条件。

以下是一些示例数据:

id <- c("0001", "0001", "0001", "0002", "0002", "0002", "0003", "0003", "0003", "0003")
dementia <- c(0, 0, 1, 0, 1, 1, 0, 1, 0, 1)
age_visit <- c("80", "81", "82","50", "51", "52","60", "61", "62", "63")
ds <- data.frame(id, dementia, age_visit)

我在长格式数据集中有二进制诊断变量dementia 看起来像这样:

    id     dementia   age_visit
1 0001        0        80
2 0001        0        81
3 0001        1        82
4 0002        0        50
5 0002        1        51
6 0002        1        52
7 0003        0        60
8 0003        1        61
9 0003        0        62

我想要一个age_at_diagnosis变量粘贴age_visit作为第一个痴呆症诊断实例,当它首先等于1.如果有一种方法可以简单地跳到最后一步是自第一次诊断以来的时间。主要问题是个体可以被诊断然后有另一个无效的评估。我想要第一个案例,然后是第一次评估以来的时间是诊断后的时间。

所以最终结果如下所示,time_sincedxage_visit - age_at_dx

     id   dementia    age_visit   age_at_dx    time_sincedx
1  0001        0        80        NA           NA
2  0001        0        81        NA           NA
3  0001        1        82        82            0
4  0002        0        50        NA           NA
5  0002        1        51        51            0
6  0002        1        52        51            1
7  0003        0        60        NA           NA
8  0003        1        61        61            0
9  0003        0        62        61            1
10 0003        1        63        61            2

有没有办法用dplyr做到这一点? 我试过这个,但这不太对。它会在每个时刻粘贴每个年龄,让我在time_since_dx列下方为零。

df <- mutate(df, age_at_dx = ifelse(dementia==1, age_at_visit, NA))
df$time_sincedx<- df$age_at_visit - df$age_atdx

任何想法都非常感激!

3 个答案:

答案 0 :(得分:2)

一个小的子集和NA来处理多余的library(tidyverse) ds %>% group_by(id) %>% # evaluate patients individually mutate(age_visit = as.integer(as.character(age_visit)), # factor to integer # if no dementia, NA else min age where dementia == 1 age_at_dx = ifelse(dementia == 0, NA, min(age_visit[dementia == 1]))) %>% fill(age_at_dx) %>% # fill in NAs after non-NA (where dx == 1, then 0 like line 9) mutate(time_since_dx = age_visit - age_at_dx) ## Source: local data frame [10 x 5] ## Groups: id [3] ## ## id dementia age_visit age_at_dx time_since_dx ## <fctr> <dbl> <int> <int> <int> ## 1 0001 0 80 NA NA ## 2 0001 0 81 NA NA ## 3 0001 1 82 82 0 ## 4 0002 0 50 NA NA ## 5 0002 1 51 51 0 ## 6 0002 1 52 51 1 ## 7 0003 0 60 NA NA ## 8 0003 1 61 61 0 ## 9 0003 0 62 61 1 ## 10 0003 1 63 61 2 值会让你到达那里:

age_at_dx

或跳过ds %>% group_by(id) %>% mutate(age_visit = as.integer(as.character(age_visit)), time_since_dx = age_visit - min(age_visit[dementia == 1]), time_since_dx = ifelse(time_since_dx < 0, NA, time_since_dx)) # make negatives NA ## Source: local data frame [10 x 4] ## Groups: id [3] ## ## id dementia age_visit time_since_dx ## <fctr> <dbl> <int> <int> ## 1 0001 0 80 NA ## 2 0001 0 81 NA ## 3 0001 1 82 0 ## 4 0002 0 50 NA ## 5 0002 1 51 0 ## 6 0002 1 52 1 ## 7 0003 0 60 NA ## 8 0003 1 61 0 ## 9 0003 0 62 1 ## 10 0003 1 63 2 列,

Address

答案 1 :(得分:1)

这是另一种方式。首先,我将age_visit转换为整数。然后,我按id对数据进行了分组。我使用索引创建了age_at_dx进行逻辑检查。我确定了使用which()出现痴呆症== 1的第一行(行号)。任何小于该行号的行号应为NA。其余行应该在标识的行中有数字。该逻辑用于创建age_at_dx。然后,我使用另一个逻辑检查创建了time_sincedx。在这种情况下,我检查了age_at_dx的每个元素是否为NA。如果元素不是NA,我在cumsum()中创建了time_sincedx的索引号。否则,我在time_sincedx中创建了NA。

library(dplyr)

mutate(ds, age_visit = as.integer(as.character(age_visit))) %>%
group_by(id) %>%
mutate(age_at_dx = if_else(row_number() < which(dementia == 1)[1],
                           NA_integer_, age_visit[dementia == 1][1]),
       time_sincedx = if_else(!is.na(age_at_dx), cumsum(!is.na(age_at_dx))-1, NA_real_))


#       id dementia age_visit age_at_dx time_sincedx
#   <fctr>    <dbl>     <int>     <int>        <dbl>
#1    0001        0        80        NA           NA
#2    0001        0        81        NA           NA
#3    0001        1        82        82            0
#4    0002        0        50        NA           NA
#5    0002        1        51        51            0
#6    0002        1        52        51            1
#7    0003        0        60        NA           NA
#8    0003        1        61        61            0
#9    0003        0        62        61            1
#10   0003        1        63        61            2

答案 2 :(得分:0)

此解决方案中没有花哨的技巧:只有几个透明的split,apply,combine方法应用程序。

第一步是确保您收到的数据集得到妥善安排,以便以后允许在错过诊断年份进行处理。 然后我们基本上填补了缺失的年份:检查滞后于前一年的阳性诊断的无效诊断。该逻辑表明,对于那一年的Null诊断和前一访问年度中相同患者ID的阳性诊断,在dementiaCorr列中将该阳性诊断值降低。关于这个逻辑的警告是,它只能涵盖一年的差距:注意 - 非常好奇地调查tidyr :: fill()的功能[顺便说一下:谢谢你,@ alistaire帮助我发现这个!]

然后,填写诊断空白后,我们可以分组并收集最低诊断年份。之后,我们将数据绑定到完整列表中,按照指示计算持续时间,并根据需要选择/排序数据帧以进行最终表达。

df <- 
    ds %>% 
    arrange(id, age_visit) %>% 
    mutate(dementiaCorr = ifelse((lag(id)==id)&lag(dementia == 1)|dementia == 1, 1, 0)) %>% 
    group_by(id) %>%
    filter(dementiaCorr == 1) %>% 
    mutate(age_at_dx = min(as.integer(age_visit))) %>%
    select(-dementia) %>% 
    right_join(ds, by = c('id', 'age_visit')) %>% 
    mutate(time_sincedx = as.integer(age_visit)-as.integer(age_at_dx)) %>% 
    select(id, dementia, age_visit, age_at_dx, time_sincedx)

或者,您只需按顺序切换操作并按照与您在问题中完成的数据开发进度非常匹配的顺序处理数据。

在这种方法中,我们再次确保正确安排数据以填补空白。然后我们分组并选择最小的诊断年龄。在将其向下修剪然后将其重新连接到原始数据集之后,我们会删除由于数据集中出现的模糊诊断值而出现的重复项。 然后我们填补空白:除非您重新执行间隙填充,否则需要注意1年之前的差距。 最后,从第一次诊断开始经过的时间是从整数转换值计算出来的,然后选择的列是有序/选择的。

df <- 
    ds %>% 
    arrange(id, age_visit) %>% 
    filter(dementia == 1) %>% 
    mutate(minageofDx = age_visit) %>%
    group_by(id) %>% 
    mutate(agedxPrep = min(minageofDx)) %>% 
    select(id, dementia, agedxPrep) %>%
    right_join(ds) %>% ungroup %>% distinct %>% 
    mutate(age_at_dx = ifelse(is.na(agedxPrep) & (lag(id)==id) & lag(dementia == 1), # Conditional
                              lag(agedxPrep), agedxPrep), # trueVal, falseVal 
           time_sincedx = as.integer(age_visit)-as.integer(age_at_dx)) %>% 
    select(id, dementia, age_visit, age_at_dx, time_sincedx)

希望这些简单,直接的方法与开放,平坦的逻辑中的任何一种都可能比对更高级编程风格的嵌套和复杂代码更有帮助。