在R中将行(剂量变化)添加到我的数据框

1tu0hz3e  于 2023-04-03  发布在  其他
关注(0)|答案(3)|浏览(90)

我正在处理我想以某种格式排列的临床数据,以便稍后使用它建模。我当前的数据集如下所示:

# create a data frame
df <- data.frame(ID = c(1,1,1,2,2,3,3,3),
                 DOSE = c(100, NA, NA, 200, NA, 300, NA, NA),
                 TIME = c(NA, 1, 2, NA, 3, NA, 1, 2),
                 Drug_concentration = c(NA, 5, 6.5, 3, 4, 8, 10, 12))
ID剂量时间药物浓度
1一百
11
1第二章六、五
1
第二章两百
第二章1
第二章
三百
1
第二章10个
十二岁

正如您所看到的,患者ID的第一行仅包含剂量,其他变量(时间,药物浓度)用句号填充。在初始行之后,剂量列得到句号,其他变量被填充。
我的问题:某些患者在整个治疗过程中发生了剂量变化。我想将这些剂量变化添加到我的数据集中,但不知道如何使用R有效地做到这一点。假设患者1在TIME = 2时将剂量从100 mg更改为50 mg,患者3在TIME = 2时将剂量从300 mg更改为500 mg。我希望我的数据集如下所示:
| ID|剂量|时间|药物浓度|
| --------------|--------------|--------------|--------------|
| 1|一百|。|。|
| 1|。|1|五|
| 1|五十|。|。|
| 1|。|第二章|六、五|
| 1|。|三|八|
| 第二章|两百|。|。|
| 第二章|。|1|三|
| 第二章|。|三|四|
| 三|三百|。|。|
| 三|。|1|八|
| 三|五百|。|。|
| 三|。|第二章|10个|
| 三|。|三|十二岁|
我试过使用dyplyr,但我不是那么好,在R可悲

fnvucqvd

fnvucqvd1#

下面是使用tidyverse的一种方法:
假设我们有:

dose_changes <- data.frame(ID = c(1, 3),
                           DOSE = c(50, 500),
                           TIME = c(2, 2))

我将为缺失的行添加TIME = 0,因为我希望确保这些行首先对每个ID进行排序。我还调整dose_changes TIME值,以确保它们的TIME X已排序,以便它出现在TIME X的任何测量之前(因为药物变化隐含地发生在之前的某个未指定的时间)。然后我合并dose_changes数据,排列y ID和TIME,填充(默认填充方向)缺失的剂量,最后删除行w/o Drug_concentration observations。

library(tidyverse)
df %>%
  mutate(TIME = if_else(is.na(TIME), 0, TIME)) %>%
  bind_rows(dose_changes %>% mutate(TIME = TIME - 0.1) %>%
  arrange(ID, TIME) %>%
  group_by(ID) %>%
  fill(DOSE) %>%
  filter(!is.na(Drug_concentration)) %>%
  ungroup()

# A tibble: 7 × 4
     ID  DOSE  TIME Drug_concentration
  <dbl> <dbl> <dbl>              <dbl>
1     1   100     1                5  
2     1    50     2                6.5
3     2   200     0                3  
4     2   200     3                4  
5     3   300     0                8  
6     3   300     1               10  
7     3   500     2               12
yhxst69z

yhxst69z2#

你想要的输出格式不适合R建模,但我假设你有一个很好的理由要求它。我过去确实使用过命令行分析包,它们以奇怪的方式要求数据。
不管怎样,给你。

library(tidyr)
library(dplyr)

df <- data.frame(
                  ID = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 3L),
                DOSE = c(100L, NA, NA, NA, 200L, NA, NA, 300L, NA, NA, NA),
                TIME = c(NA, 1L, 2L, 3L, NA, 1L, 3L, NA, 1L, 2L, 3L),
  Drug.concentration = c(NA, 5, 6.5, 8, NA, 3, 4, NA, 8, 10, 12)
      )

good_table <- 
    df %>%
    # 1. Fill NAs
    group_by(ID) %>% 
    fill(everything(), .direction = "down") %>% 
    ungroup() %>% 
    # 2. Add a timepoint zero for sorting
    mutate(TIME = replace_na(TIME, 0)) %>% 
    # 3. Replace NAs in Drug.concentration with -99 so that they sort to the top.
    mutate(Drug.concentration = replace_na(Drug.concentration, -99)) %>% 
    # 4. Add your rows
    add_row(ID   = c(1, 3), 
            DOSE = c(50, 500), 
            TIME = c(2, 2), 
            Drug.concentration = c(-99, -99)) %>% 
    # 5. Arrange the output so that it is in the order you want.
    arrange(ID, TIME, Drug.concentration)

good_table
#> # A tibble: 13 × 4
#>       ID  DOSE  TIME Drug.concentration
#>    <dbl> <dbl> <dbl>              <dbl>
#>  1     1   100     0              -99  
#>  2     1   100     1                5  
#>  3     1    50     2              -99  
#>  4     1   100     2                6.5
#>  5     1   100     3                8  
#>  6     2   200     0              -99  
#>  7     2   200     1                3  
#>  8     2   200     3                4  
#>  9     3   300     0              -99  
#> 10     3   300     1                8  
#> 11     3   500     2              -99  
#> 12     3   300     2               10  
#> 13     3   300     3               12

output_table <-
    good_table %>% 
    # 6. Everything has to be Character type for your dots
    mutate(across(everything(), as.character)) %>% 
    # 7. Only the first original values of DOSE are kept.
    mutate(DOSE = if_else(duplicated(DOSE), ".", DOSE)) %>% 
    # 8. If DOSE is . , then keep its values
    mutate(across(c(TIME, Drug.concentration), 
                  function(orig_value) {
                      if_else(DOSE == ".", orig_value, ".")
                  }))

output_table
#> # A tibble: 13 × 4
#>    ID    DOSE  TIME  Drug.concentration
#>    <chr> <chr> <chr> <chr>             
#>  1 1     100   .     .                 
#>  2 1     .     1     5                 
#>  3 1     50    .     .                 
#>  4 1     .     2     6.5               
#>  5 1     .     3     8                 
#>  6 2     200   .     .                 
#>  7 2     .     1     3                 
#>  8 2     .     3     4                 
#>  9 3     300   .     .                 
#> 10 3     .     1     8                 
#> 11 3     500   .     .                 
#> 12 3     .     2     10                
#> 13 3     .     3     12

创建于2023-04-01使用reprex v2.0.2
PS.你给出的生成df的第一组代码是错误的,它没有生成你粘贴在它下面的表。下次请仔细检查。你的代码也生成了NA而不是点,不像它下面的表。我为这个例子保留了NA,但如果你的数据实际上有点,然后你需要在第13行和第14行之间插入它来创建NA并将数据转换成正确的类型。

mutate(across(c(ID, DOSE, TIME), as.integer)) %>% 
    mutate(across(Drug.concentration, as.numeric)) %>%
68bkxrlz

68bkxrlz3#

您可以使用which获取行,然后使用rbind插入行。

i <- which(df$ID == 1 & df$TIME == 2)
df <- rbind(df[1:(i-1),], setNames(data.frame(1, 50, NA, NA), names(df)), df[i:nrow(df),])

i <- which(df$ID == 3 & df$TIME == 2)
df <- rbind(df[1:(i-1),], setNames(data.frame(3, 500, NA, NA), names(df)), df[i:nrow(df),])

df
#   ID DOSE TIME Drug_concentration
#1   1  100   NA                 NA
#2   1   NA    1                5.0
#3   1   50   NA                 NA
#31  1   NA    2                6.5
#4   2  200   NA                3.0
#5   2   NA    3                4.0
#6   3  300   NA                8.0
#7   3   NA    1               10.0
#11  3  500   NA                 NA
#8   3   NA    2               12.0

相关问题