如何按日期而不是个人使处方数据框更宽

How to make prescription data frame wider in r by date, not by individual

我有长格式的患者处方数据,想创建一个更宽的数据框,其中每一行代表不同的处方交付。所以有些患者只有一排,但多次分娩的患者会有几排(每次处方分娩一排)。我以前只以非常简单的方式使用过 pivot 命令,但我很挣扎,因为我只为每个患者返回 1 行,而我想要为每个患者的每个处方交付日期返回 1 行。

我有一个非常简单的数据框,包含患者 ID、处方交付日期以及与他们收到的处方对应的代码。

id = id = factor(c("1001","1001","1001","1002","1002","1002","1002","1002","1003","1003"))
date = c("2013-10-31","2013-11-30","2013-12-31","2013-08-28","2013-08-28","2013-09-30",
         "2013-09-30","2013-02-15","2013-02-15","2013-02-15")
atc_code = c("C07AA05","C07AA05","C07AA05","A10BA02","C09CA01","A10BA02",
                       "C09CA01","A10BA02","A10BA02","C07AA05")

date1 <- as.Date(date, format = "%Y-%m-%d")
df <- data.frame(id,
                 date1,
                atc_code)
df
#>      id      date1 atc_code
#> 1  1001 2013-10-31  C07AA05
#> 2  1001 2013-11-30  C07AA05
#> 3  1001 2013-12-31  C07AA05
#> 4  1002 2013-08-28  A10BA02
#> 5  1002 2013-08-28  C09CA01
#> 6  1002 2013-09-30  A10BA02
#> 7  1002 2013-09-30  C09CA01
#> 8  1002 2013-02-15  A10BA02
#> 9  1003 2013-02-15  A10BA02
#> 10 1003 2013-02-15  C07AA05
Created on 2021-12-04 by the reprex package (v2.0.1)

我希望数据框看起来像什么:

df
#>     id       date atc_code_1 atc_code_2
#> 1 1001 2013-10-31    C07AA05         NA
#> 2 1001 2013-11-30    C07AA05         NA
#> 3 1001 2013-12-31    C07AA05         NA
#> 4 1002 2013-08-28    A10BA02    C09CA01
#> 5 1002 2013-09-30    A10BA02    C09CA01
#> 6 1002 2013-02-15    A10BA02         NA
#> 7 1003 2013-02-15    A10BA02    C07AA05

在现实中,一个病人一年可以分娩很多次,一次分娩可以开很多次处方,但我为了这个例子尽量简单。任何帮助将不胜感激。

我需要做的是创建一个带有变异(一种疾病)的新变量,该变量使用单次交付中的处方组合来定义(即患者是否获得了 x 和 y 处方,或者他们获得了 x 而不是 y处方),因此如果这可以通过一系列 group_bys 或其他方式实现,那也可以。

谢谢!

使用data.table:
(记录的顺序和你想要的不一样)

library(data.table)
setDT(df)
dcast(df, id + date1 ~ rowid(id, date1, prefix = 'atc_code_'), 
      value.var = 'atc_code')

    id      date1 atc_code_1 atc_code_2
1: 1001 2013-10-31    C07AA05       <NA>
2: 1001 2013-11-30    C07AA05       <NA>
3: 1001 2013-12-31    C07AA05       <NA>
4: 1002 2013-02-15    A10BA02       <NA>
5: 1002 2013-08-28    A10BA02    C09CA01
6: 1002 2013-09-30    A10BA02    C09CA01
7: 1003 2013-02-15    A10BA02    C07AA05

我想这就是你想要的:

library(tidyverse)
df <- df %>% group_by(id, date1) %>% mutate(num_scripts = row_number())
df_wide <- df %>% pivot_wider(names_from = num_scripts, values_from = atc_code)

编辑:更改了列名以匹配您的

df_wide <- df %>% pivot_wider(names_from = num_scripts, values_from = atc_code, names_prefix = "atc_code_")

考虑 ave 添加 运行 组计数 iddate1 分组,然后 reshape 宽。 (num 以下需要作为 ave 的临时变量,但可以使用任何数字字段。)

df <- within(df, {
  atc_num <- ave(1:nrow(df), id, date1, FUN=seq_along)
}) |> reshape(
  idvar = c("id", "date1"),
  timevar = "atc_num",
  direction = "wide"
) 

df
    id      date1 atc_code.1 atc_code.2
1 1001 2013-10-31    C07AA05       <NA>
2 1001 2013-11-30    C07AA05       <NA>
3 1001 2013-12-31    C07AA05       <NA>
4 1002 2013-08-28    A10BA02    C09CA01
6 1002 2013-09-30    A10BA02    C09CA01
8 1002 2013-02-15    A10BA02       <NA>
9 1003 2013-02-15    A10BA02    C07AA05

您可以使用 tidyverse。对于每个组(即 iddate1),我们 mutate 一个新列来指定每个记录(我们将使用它来转向新列)。然后,您可以使用 pivot_widercategory 名称以及 atc_codes 来输入所需的格式。

library(tidyverse)

df %>%
  dplyr::group_by(id, date1) %>%
  dplyr::mutate(category = paste0("atc_code_", 1:n())) %>%
  tidyr::pivot_wider(names_from = category, values_from = atc_code) %>%
  dplyr::arrange(id, date1)

输出

# A tibble: 7 × 4
# Groups:   id [3]
  id    date1      atc_code_1 atc_code_2
  <fct> <date>     <chr>      <chr>     
1 1001  2013-10-31 C07AA05    NA        
2 1001  2013-11-30 C07AA05    NA        
3 1001  2013-12-31 C07AA05    NA        
4 1002  2013-02-15 A10BA02    NA        
5 1002  2013-08-28 A10BA02    C09CA01   
6 1002  2013-09-30 A10BA02    C09CA01   
7 1003  2013-02-15 A10BA02    C07AA05  

数据

df <- structure(
  list(
    id = structure(
      c(1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L,
        3L, 3L),
      .Label = c("1001", "1002", "1003"),
      class = "factor"
    ),
    date1 = structure(
      c(
        16009, 16039, 16070, 15945, 15945, 15978, 15978, 
        15751, 15751, 15751
      ),
      class = "Date"
    ),
    atc_code = c(
      "C07AA05", "C07AA05",  "C07AA05", "A10BA02", "C09CA01", 
      "A10BA02", "C09CA01", "A10BA02", "A10BA02", "C07AA05"
    )
  ),
  class = "data.frame",
  row.names = c(NA, -10L)
)