如何在R中选择组内两个变量的特定值组合的行。

3
这是我之前提出的一个 R 问题的扩展:如何在 R 中选择特定组内具有特定值的行 我得到了很好的帮助,但现在情况变得更加复杂,我希望能够得到处理此问题的建议。
我的数据看起来像这样:
dd <- read.table(text="
    event.timeline.ys     ID     year    group  outcome
                 1                   2     800033 2008    A  3
                 2                   1     800033 2009    A  3
                 3                   0     800033 2010    A  NA   
                 4                  -1     800033 2011    A  2  
                 5                  -2     800033 2012    A  1  
                 15                  0     800076 2008    B  2
                 16                 -1     800076 2009    B  NA
                 17                  5     800100 2014    C  4     
                 18                  4     800100 2015    C  4  
                 19                  2     800100 2017    C  4  
                 20                  1     800100 2018    C  3   
                 30                  0     800125 2008    A  2   
                 31                 -1     800125 2009    A  1   
                 32                 -2     800125 2010    A  NA
                 33                  2     800031 2008    A  3
                 34                  1     800031 2009    A  3
                 35                  0     800031 2010    A  NA   
                 36                 -1     800031 2011    A  NA  
                 37                 -2     800031 2012    A  1", header=TRUE)

我希望只选择组(ID)内的特殊行。这些行应根据以下过程选择:
如果可能,我想保留每个参与者(即,在具有事件时间轴上ys值≥0的ID组中的最后一行),其结果变量不是NA但具有有效值的最后一行(例如,对于ID == 800033,这将是第2行)。
此外,我想保留每个参与者的第一行,其中事件时间轴上ys值小于0且结果变量不是NA(即,在具有事件时间轴上ys值<0的ID组中的第一行;例如,对于ID == 800033,这将是第4行)。
在ID == 800076的特殊情况下,当事件时间轴.ys < 0时没有任何非NA值的结果变量,我仍然希望保留事件时间轴.ys < 0的第一行。
ID = 800100的人在事件时间轴.ys上没有任何负值。在这种情况下,我只想保留事件时间轴上ys值≥0的最后一行。
所有其他行应该被删除。最终数据框应该是这样的:
      event.timeline.ys         ID     year    group  outcome
2                     1     800033     2009    A            3
4                    -1     800033     2011    A            2  
15                    0     800076     2008    B            2
16                   -1     800076     2009    B           NA
20                    1     800100     2018    C            3   
30                    0     800125     2008    A            2   
31                   -1     800125     2009    A            1
34                    1     800031     2009    A            3
37                   -2     800031     2012    A            1

我非常感谢有关如何解决这个问题的建议。我已经尝试过以下方法:
dd %>% 
  group_by(ID) %>% 
  filter(row_number() == last(which(event.timeline.ys >= 0 & outcome >= 0)) | 
           row_number() == first(which(event.timeline.ys < 0 & outcome >= 0)))

然而,我会失去第16行(对于ID == 800076),这是不幸的。提前感谢您!
3个回答

1
这里是使用dplyrwrapr的管道%.>%的解决方案。 我正在添加outcome_na并按它进行排序,以满足“没有任何非NA值”的条件。
library(dplyr)
library(wrapr)

dd %>%
  group_by(ID) %>%
  mutate(outcome_na = !is.na(outcome)) %.>%
  bind_rows(
    filter(., event.timeline.ys >= 0) %>% arrange(outcome_na, year) %>% slice(n()),
    filter(., event.timeline.ys < 0) %>% arrange(desc(outcome_na), year) %>% slice(1)
  ) %>%
  arrange(ID) %>%
  select(-outcome_na)

嘿,我在上面的数据示例中添加了另一个人(ID == 800031)。使用您的代码,我将获得第34行(正确的行)和第36行。但是,在第36行中,这个人在结果变量上有NA。我想要获取第37行(具有事件时间轴.ys上负值且结果变量具有有效值的第一行)。我需要如何调整您的代码才能实现这一点? - Marie B.
@MarieB。您需要按outcome_naevent.timeline.ys < 0进行排序,但这次是按降序排列,因为您想要的不是最后一行,而是第一行。 - Paweł Chabros

1
使用 dplyr
dd %>%
group_by(ID, event.timeline.ys>=0) %>%
arrange(ID, event.timeline.ys>=0, abs(event.timeline.ys)) %>%
filter(!is.na(outcome) | n()==1) %>%
filter(row_number()==1) %>%
ungroup() %>%
select(-one_of('event.timeline.ys >= 0'))

输出:

  event.timeline.ys     ID  year group outcome
              <int>  <int> <int> <fct>   <int>
1                -1 800033  2011 A           2
2                 1 800033  2009 A           3
3                -1 800076  2009 B          NA
4                 0 800076  2008 B           2
5                 1 800100  2018 C           3
6                -1 800125  2009 A           1
7                 0 800125  2008 A           2

1
非常感谢!我真的很感激你的帮助。我喜欢看到有不同的方法可以得到相同的结果。对于一些不太熟悉管道、函数和循环(像我这样,我刚开始自学R)的人来说,这也看起来是一个清晰简单的解决方案! - Marie B.

1

为了与我之前的回答保持一致,使用data.table,我们可以使用ifelse条件来选择行。

library(data.table)
setDT(dd)
dd[, .SD[na.omit(c(ifelse(any(event.timeline.ys >= 0 & !is.na(outcome)),
                          last(which(event.timeline.ys >= 0 & !is.na(outcome))), 
                          last(which(event.timeline.ys >= 0))),
                   ifelse(any(event.timeline.ys < 0 & !is.na(outcome)),
                          first(which(event.timeline.ys < 0 & !is.na(outcome))), 
                          first(which(event.timeline.ys < 0)))))],
   by=ID]


       ID event.timeline.ys year group outcome
1: 800033                 1 2009     A       3
2: 800033                -1 2011     A       2
3: 800076                 0 2008     B       2
4: 800076                -1 2009     B      NA
5: 800100                 1 2018     C       3
6: 800125                 0 2008     A       2
7: 800125                -1 2009     A       1
8: 800031                 1 2009     A       3
9: 800031                -2 2012     A       1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接