按 ID 和结果分组,取特定结果的最早日期并分配数字(即结果 1、结果 2)

Posted

技术标签:

【中文标题】按 ID 和结果分组,取特定结果的最早日期并分配数字(即结果 1、结果 2)【英文标题】:Group by ID and Outcome and take the earliest earliest Dates of specific outcomes and assign numbers (i.e outcome1, outcome2) 【发布时间】:2022-01-02 07:17:02 【问题描述】:

抱歉,如果我没有清楚地解释这一点。 但我有以下数据集:

mydata = data.frame (Id =c (1,1,1,1,1,1,1,1,2,2,2,2),
Date = c("2001-01-31", "2001-02-13","2001-05-31",
"2001-06-02","2018-01-31","2018-03-31","2018-07-31",
"2019-04-04","2014-01-31","2014-02-02","2014-04-31",
"2014-05-18"),Outcome = c("CR","CR","Relapse","Relapse",
"CR","CR","CR","Relapse","CR", "CR","Relapse","CR"))

输出以下内容。如您所见,每位患者在不同时间处于某些阶段,我想记录每位患者每个新阶段开始的最早日期。然后我想将这些阶段重命名为 CR1、Relapse1、CR2、Relapse2 等等。

Id     Date        Outcome
1   2001-01-31  CR      
1   2001-02-13  CR      
1   2001-05-31  Relapse     
1   2001-06-02  Relapse     
1   2018-01-31  CR      
1   2018-03-31  CR      
1   2018-07-31  CR      
1   2019-04-04  Relapse     
2   2014-01-31  CR      
2   2014-02-02  CR
2   2014-04-31  Relapse     
2   2014-05-18  CR      
 

这是我想要达到的输出:

Id     CR1       Relapse1      CR2       Relapse2
1   2001-01-31  2001-05-31  2018-01-31  2019-04-04
2   2014-01-31  2014-04-31  2014-05-18  NA

我不太确定从哪里开始提出这个问题,如果有任何帮助,我将不胜感激!谢谢各位!

【问题讨论】:

您是指每个 ID 年份结果组合中最早的一个吗?还是每个 ID 结果的最早和最晚? 最终结果变量的顺序重要吗?即,如果您获得 CR1、CR2、Relapese1、Relapse2,这有关系吗? @Macosso 每个 ID 和结果组合的最早日期 在它们切换到另一个结果之前。 @NicolásVelásquez 是的,复发前的第一个 CR 应标记为 CR1,之后应标记为 relapse1。如果他们在复发后再次达到CR,应该是CR2等等 对此的后续问题,是否有可能仅在看到第一个 CR 后才开始计数?因此,如果一个 id 在 CR 之前有 Relapse 将被忽略,然后在第一个 CR 之后的第一次复发将被视为 Relapse 1?谢谢!! —— 【参考方案1】:

使用tidyverse,您可以尝试以下操作。

(如果需要,首先 arrangeDate 按时间顺序排列。)

根据Outcome 列中的变化创建一个分组值(从缓解到复发,反之亦然)。为了方便起见,我使用了data.table 中的rleid,并创建了一个临时列Grp。例如:

      Id Date       Outcome   Grp
   <dbl> <chr>      <chr>   <int>
 1     1 2001-01-31 CR          1
 2     1 2001-02-13 CR          1
 3     1 2001-05-31 Relapse     2
 4     1 2001-06-02 Relapse     2
 5     1 2018-01-31 CR          3
 6     1 2018-03-31 CR          3
 7     1 2018-07-31 CR          3
 8     1 2019-04-04 Relapse     4
 9     2 2014-01-31 CR          1
10     2 2014-02-02 CR          1
11     2 2014-04-31 Relapse     2
12     2 2014-05-18 CR          3

您可以看到,在每个Id 中,当Outcome 更改时,Grp 会增加。这样,具有相同Outcome 的后续日期将包含在相同的Grp 中。

.add 参数允许我们将 Grp 添加到之前的分组中,即 Id。因此,现在按GrpId 分组,然后您可以slice 第一行。 slice(1)slice(n = 1) 将在组内保留 1 行。在这种情况下,我们同时按IdGrp 进行分组,因此对于给定的GrpId 组合只会保留1 行。

最后,您可以添加一个允许所描述的宽输出的行号(CR 和复发的连续数字序列:1、2、3、4...)。在这种情况下,我们group_by 同时IdOutcome,并为这个组合连续编号日期。如果需要,pivot_wider 会将数据转换为宽格式。

library(data.table)
library(tidyverse)

mydata %>%
  group_by(Id) %>%
  mutate(Grp = rleid(Outcome)) %>%
  group_by(Grp, .add = T) %>%
  slice(1) %>%
  group_by(Id, Outcome) %>%
  mutate(n = row_number()) %>%
  pivot_wider(id_cols = Id, names_from = c(Outcome, n), values_from = Date)

输出

     Id CR_1       Relapse_1  CR_2       Relapse_2 
  <dbl> <chr>      <chr>      <chr>      <chr>     
1     1 2001-01-31 2001-05-31 2018-01-31 2019-04-04
2     2 2014-01-31 2014-04-31 2014-05-18 NA  

【讨论】:

谢谢!我试过了,但一直收到以下错误:``` 错误:在group_by() 中添加计算列时出现问题。 x mutate() 输入 Grp 有问题。 x找不到函数“rleid”ℹ输入Grprleid(Outcome)``` @Ben,啊,你比我快 3 分钟 :( 无论如何我只能使用子集和 shitf() 函数来解决它。你能解释一下这条线:group_by(Grp = rleid(Outcome), .add = T) %&gt;% 做什么? 还有slice(1) @Ben 效果很好,非常感谢! @Ben 非常有帮助! 已编辑,以便 rleid 编号随着 Id 的更改重新启动。

以上是关于按 ID 和结果分组,取特定结果的最早日期并分配数字(即结果 1、结果 2)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SQL 中按多列分组并按日期排序?

SQL Server - 在按特定列分组时构建动态范围的数字

使用子查询按特定列分组输出相同的错误结果

我需要连接三个表,将结果按一列分组,并显示另一列的最大值

Python 按两列分组,然后获取最早和最晚日期

如何使用 Linq 按日期时间和平均结果对字典进行分组