【问题标题】:Selecting the first positive event选择第一个积极事件
【发布时间】:2021-01-25 09:43:21
【问题描述】:

我正在苦苦思考如何仅使用基于日期的第一个正面测试来创建数据框的子样本。我将展示一个玩具示例。假设我有以下内容;

df = data.frame(guy = c("A", "B", "A", 'B', "C", "C"),
  test1 = c(1, 1, 0, 0, 1, 0),
                test2 = c(0, 1, 0, 1, 0, 0),
                test3 = c(0, 0, 1, 0, 0, 1),
                date = as.Date(c('1999-10-20', '1999-10-21', '1999-10-22', '1999-10-23', '1999-10-24', '1999-10-25')));df
   #guy test1 test2 test3       date
#1   A     1     0     0 1999-10-20
#2   B     1     1     0 1999-10-21
#3   A     0     0     1 1999-10-22
#4   B     0     1     0 1999-10-23
#5   C     1     0     0 1999-10-24
#6   C     0     0     1 1999-10-25

现在,我想过滤,根据最旧的 date 仅选择第一个阳性测试(即 test1|test2|test3 = 1)。在我的示例中,我会得到以下信息:

   #guy test1 test2 test3       date
#1   A     1     0     0 1999-10-20
#2   B     1     1     0 1999-10-21
#3   C     1     0     0 1999-10-24

数据框:

df = data.frame(guy = c("A", "B", "A", 'B', "C", "C"),
  test1 = c(1, 1, 0, 0, 1, 0),
                test2 = c(0, 1, 0, 1, 0, 0),
                test3 = c(0, 0, 1, 0, 0, 1),
                date = as.Date(c('1999-10-20', '1999-10-21', '1999-10-22', '1999-10-23', '1999-10-24', '1999-10-25')));df

任何提示我该怎么做?

【问题讨论】:

  • 为什么sqlite被标记在这里?
  • test1 列有字符串 A、B 和 C,您需要如何将其与 1 进行比较?

标签: r database dataframe select filter


【解决方案1】:

使用dplyr::top_n 另一个选项是:

df = data.frame(guy = c("A", "B", "A", 'B', "C", "C"),
                test1 = c(1, 1, 0, 0, 1, 0),
                test2 = c(0, 1, 0, 1, 0, 0),
                test3 = c(0, 0, 1, 0, 0, 1),
                date = as.Date(c('1999-10-20', '1999-10-21', '1999-10-22', '1999-10-23', '1999-10-24', '1999-10-25')))

library(dplyr)

df %>% 
  filter(test1 | test2 | test3) %>% 
  group_by(guy) %>% 
  top_n(-1, date)
#> # A tibble: 3 x 5
#> # Groups:   guy [3]
#>   guy   test1 test2 test3 date      
#>   <chr> <dbl> <dbl> <dbl> <date>    
#> 1 A         1     0     0 1999-10-20
#> 2 B         1     1     0 1999-10-21
#> 3 C         1     0     0 1999-10-24

【讨论】:

    【解决方案2】:

    使用subset + ave + max.col 的基本 R 选项

    subset(
      df,
      as.logical(
        ave(
          max.col(df[grepl("test\\d+", names(df))], "first"),
          guy,
          FUN = function(x) x == min(x)
        )
      ) & (test1|test2|test3)
    )
    

    给了

      guy test1 test2 test3       date
    1   A     1     0     0 1999-10-20
    2   B     1     1     0 1999-10-21
    5   C     1     0     0 1999-10-24
    

    【讨论】:

    • @akrun 是的,你的理解是对的。 OP 想找出test1test2test3(按guy 分组)中的第一个正值并获取该行
    • @akrun 奥基,我明白了。谢谢你纠正我。我会努力解决这个问题
    • @akrun 我想现在它会是一个安全的版本
    【解决方案3】:

    dplyr 1.0.0 用于任何个您可以执行的test 列:

    library(dplyr)
    
    df %>%
      group_by(guy) %>%
      slice(which.max(rowSums(select(cur_data(), starts_with('test'))) > 0))
    
    
    #   guy   test1 test2 test3 date      
    #  <chr> <dbl> <dbl> <dbl> <date>    
    #1 A         1     0     0 1999-10-20
    #2 B         1     1     0 1999-10-21
    #3 C         1     0     0 1999-10-24
    

    以上假设您在每个 guy 中至少有一行,其中包含 1。如果不是这种情况,则意味着您可以拥有一个没有任何 1 的 guy,您可以使用 match

    df %>%
      group_by(guy) %>%
      slice(match(TRUE, rowSums(select(cur_data(), starts_with('test'))) > 0))
    

    【讨论】:

      【解决方案4】:

      另一种方法可以使用inner_join() 完成,并将数据重新整形为 long 以识别旧日期和值。代码如下:

      library(tidyverse)
      #Code
      dfout <- df %>% inner_join(df %>% pivot_longer(-c(guy,date)) %>% group_by(guy,name) %>%
        filter(date==min(date) & value==1) %>% ungroup() %>%
        group_by(guy) %>%
        filter(!duplicated(value)) %>% select(-c(name,value)))
      

      输出:

        guy test1 test2 test3       date
      1   A     1     0     0 1999-10-20
      2   B     1     1     0 1999-10-21
      3   C     1     0     0 1999-10-24
      

      【讨论】:

        【解决方案5】:

        base R 的选项

        subset(df, seq_len(nrow(df)) == ave(seq_len(nrow(df)) *
               (test1|test2|test3), guy, FUN = min))
        #   guy test1 test2 test3       date
        #1   A     1     0     0 1999-10-20
        #2   B     1     1     0 1999-10-21
        #5   C     1     0     0 1999-10-24
        

        【讨论】:

        • 这是一个非常简单的基础 R 解决方案,喜欢它!
        【解决方案6】:

        试试:

        library(dplyr)
        df %>% filter(test1 | test2 | test3 ) %>% 
               arrange(date) %>% group_by(guy) %>% 
               summarize(first(date),first(test1),first(test2),first(test3)) %>%
               ungroup
        
        # A tibble: 3 x 5
          guy   `first(date)` `first(test1)` `first(test2)` `first(test3)`
          <chr> <date>                 <dbl>          <dbl>          <dbl>
        1 A     1999-10-20                 1              0              0
        2 B     1999-10-21                 1              1              0
        3 C     1999-10-24                 1              0              0
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-02-20
          • 2013-07-19
          • 2016-04-05
          • 1970-01-01
          • 2011-08-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多