R使用来自第二个tibble的数据作为行和列更新一个tibble

R update a tibble using data from a second tibble as row and column

我有一个充满 NA 的空标题,其中包含行和列,分别以 ID 号和一段时间内的所有日期命名。例如,这段代码:

tbl <- tibble(PERSONAL_ID = c("A", "B", "C", "D"))
dates = as.character((seq(as.Date("2016-01-01"), as.Date("2016-01-05"), by="days")))
tbl[dates] <- NA
tbl <- column_to_rownames(tbl, var = "PERSONAL_ID")

我有第二个 tibble,其中包含将一个 ID 号与一个日期匹配的列,如本例所示:

enrollments <- tibble(ID = c("D", "B", "C", "D"),
                      date = c("2016-01-01", "2016-01-03", "2016-01-05", "2016-01-02"))

我想做的是将“1”添加到与第二个标题(注册)中列出的 ID 和日期相对应的第一个标题 (tbl) 的行和列。对于上面的示例代码,所需的输出将是:

  2016-01-01 2016-01-02 2016-01-03 2016-01-04 2016-01-05
A       <NA>       <NA>       <NA>        <NA>      <NA>
B       <NA>       <NA>          1        <NA>      <NA>
C       <NA>       <NA>       <NA>        <NA>         1
D          1          1       <NA>        <NA>      <NA>

谢谢!

这是一个 tidyverse 方法。

  1. 首先将您的 tblwide 格式更改为 long 格式,使其与 enrollments.
  2. 的格式匹配
  3. enrollments 中创建一个 Count 列,每一行都是 Count = 1
  4. 然后 left_join 转换后的 tblenrollments 使用 IDdate 作为连接字段。
  5. 最后,将 long 格式转换回 wide 格式并设置 rownames
library(tidyverse)

left_join(tbl %>% rownames_to_column(var = "ID") %>% 
            pivot_longer(-ID, names_to = "date", values_to = "Count") %>% 
            select(-Count), 
          enrollments %>% mutate(Count = 1), 
          by = c("ID", "date")) %>%
  pivot_wider(names_from = "date", values_from = "Count") %>%
  column_to_rownames(var = "ID")

输出

 2016-01-01 2016-01-02 2016-01-03 2016-01-04 2016-01-05
A         NA         NA         NA         NA         NA
B         NA         NA          1         NA         NA
C         NA         NA         NA         NA          1
D          1          1         NA         NA         NA

您的数据集作为参考

tbl
  2016-01-01 2016-01-02 2016-01-03 2016-01-04 2016-01-05
A         NA         NA         NA         NA         NA
B         NA         NA         NA         NA         NA
C         NA         NA         NA         NA         NA
D         NA         NA         NA         NA         NA
enrollments
# A tibble: 4 x 2
  ID    date      
  <chr> <chr>     
1 D     2016-01-01
2 B     2016-01-03
3 C     2016-01-05
4 D     2016-01-02

这是一个基本的 R 方法。对于注册,我将每一行的 dateID 组合成一个字符串。然后,对于 tbl,我创建了一个用日期和行名填充的 table。然后,我使用 matchenrollment 中的值与 tbl 中的值相匹配。我使用 arrayInd 来获取列和行索引。最后,我 replace tbl 中的 NA 值和 1 用于提取的 column-row 索引。

replace(tbl, arrayInd(match(do.call(
  paste, subset(enrollments, select = c("date", "ID"))),
t(outer(colnames(tbl), rownames(tbl), FUN = paste)
)), .dim = dim(tbl)), 1)

这里有一个稍微不同的 tidyverse 方法,使用 rows_update。在这里,我将 enrollments 转换为宽格式,然后绑定到 tbl(但没有行)以便具有相同的列。然后,我使用 enrollments.

中的新格式更新 tbl 中的行
library(tidyverse)

rows_update(tbl %>% rownames_to_column("ID"), enrollments %>% 
              mutate(value = 1) %>% 
              pivot_wider(names_from = "date", values_from = "value") %>% 
              bind_rows(tbl[0,])) %>% 
  column_to_rownames("ID")

输出

  2016-01-01 2016-01-02 2016-01-03 2016-01-04 2016-01-05
A         NA         NA         NA         NA         NA
B         NA         NA          1         NA         NA
C         NA         NA         NA         NA          1
D          1          1         NA         NA         NA

这是一个 data.table 方法,使用 PERSONAL_IDSdatesenrollments

dcast(rbind(
  rbindlist(lapply(setdiff(PERSONAL_ID,enrollments$ID), \(x) data.table(ID=x, date=dates)))[,value:=NA],
  enrollments[,value:=1]
  ), ID~date,value.var="value")

输出:

   ID 2016-01-01 2016-01-02 2016-01-03 2016-01-04 2016-01-05
1:  A         NA         NA         NA         NA         NA
2:  B         NA         NA          1         NA         NA
3:  C         NA         NA         NA         NA          1
4:  D          1          1         NA         NA         NA