【问题标题】:Generalizing a data.frame subsetting function泛化 data.frame 子集函数
【发布时间】:2021-10-03 15:43:23
【问题描述】:

我有一个玩具 data.frame,它有 4 列(study,outcome,group,time)。比如说,用户想知道在哪些唯一 study 值中,其他任何选定的列值是恒定的还是变化的。

例如,如果用户想知道哪些唯一的study 值、outcomegroup 列值是恒定的还是变化的,那么我们知道可能有 4 种情况:

  1. group 不变,但 outcome 变化。
  2. outcome 不变,但 group 变化。
  3. outcomegroup 都不同。
  4. outcomegroup 两者都没有变化。

下面的函数foo,正是基于上面的例子。

问题:我想知道如何概括foo,以便用户可以在函数中输入他选择的列的名称(例如outcomegroup),以及@987654341 @ 自动检查在哪些唯一 study 值中,任何选定的列是恒定的还是变化的?

ps。在下面的示例中,我的泛化函数将产生如下所示的相同输出。

h = "
study outcome group time
a     1       1     0
a     2       1     1
b     1       1     0
b     1       2     0
c     2       1     0
c     3       2     1
d     1       1     0
d     1       1     0
e     1       1     0"
h = read.table(text=h,h=T)

foo <- function(dat, cond) {
  
  switch(cond, 
         
         `1` = dat %>% 
           group_by(study) %>%
           filter(n_distinct(group) == 1, n_distinct(outcome) > 1) %>%
           ungroup,
         `2` = dat %>% 
           group_by(study) %>%
           filter(n_distinct(group) > 1, n_distinct(outcome) == 1) %>%
           ungroup,
         
         `3` =  dat %>% 
           group_by(study) %>%
           filter(n_distinct(group) > 1, n_distinct(outcome) > 1) %>%
           ungroup,
         `4` = dat %>% 
           group_by(study) %>%
           filter(n_distinct(group) == 1, n_distinct(outcome) == 1) %>%
           ungroup )  } 

#------------------- EXAMPLE OF USE:
> foo(h, 1)
# A tibble: 2 x 3
  study outcome group
  <chr>   <int> <int>
1 a           1     1
2 a           2     1
> foo(h, 2)
# A tibble: 2 x 3
  study outcome group
  <chr>   <int> <int>
1 b           1     1
2 b           1     2
> foo(h, 3)
# A tibble: 2 x 3
  study outcome group
  <chr>   <int> <int>
1 c           2     1
2 c           3     2
> foo(h, 4)
# A tibble: 3 x 3
  study outcome group
  <chr>   <int> <int>
1 d           1     1
2 d           1     1
3 e           1     1

【问题讨论】:

    标签: r dataframe function dplyr tidyverse


    【解决方案1】:

    如果输入参数未加引号,请使用{{}}

    foo <- function(dat, study_col, group_col, outcome_col) {
      
      fn1 <- function(cond) {
               switch(cond, 
             
             `1` = dat %>% 
               group_by({{study_col}}) %>%
               filter(n_distinct({{group_col}}) == 1, n_distinct({{outcome_col}}) > 1) %>%
               ungroup,
             `2` = dat %>% 
               group_by({{study_col}}) %>%
               filter(n_distinct({{group_col}}) > 1, n_distinct({{outcome_col}}) == 1) %>%
          ungroup,
             `3` = dat %>% 
               group_by({{study_col}}) %>%
               filter(n_distinct({{group_col}}) > 1, n_distinct({{outcome_col}}) > 1) %>%
          ungroup,
             
             `4` = dat %>% 
               group_by({{study_col}}) %>%
               filter(n_distinct({{group_col}}) == 1, n_distinct({{outcome_col}}) == 1) %>%
          ungroup
             )  }
         purrr::map(1:4, ~ fn1(.x))
    
    }
    

    -测试

    > foo(h, study, group, outcome)
    [[1]]
    # A tibble: 2 x 4
      study outcome group  time
      <chr>   <int> <int> <int>
    1 a           1     1     0
    2 a           2     1     1
    
    [[2]]
    # A tibble: 2 x 4
      study outcome group  time
      <chr>   <int> <int> <int>
    1 b           1     1     0
    2 b           1     2     0
    
    [[3]]
    # A tibble: 2 x 4
      study outcome group  time
      <chr>   <int> <int> <int>
    1 c           2     1     0
    2 c           3     2     1
    
    [[4]]
    # A tibble: 3 x 4
      study outcome group  time
      <chr>   <int> <int> <int>
    1 d           1     1     0
    2 d           1     1     0
    3 e           1     1     0
    

    或者使用

    foo2 <- function(dat, study_col, group_col, outcome_col) {
    
        dat %>%
               dplyr::select({{study_col}}, {{group_col}}, {{outcome_col}}) %>%
               dplyr::group_by({{study_col}}) %>%
              dplyr::mutate(grp = stringr::str_c(n_distinct({{group_col}}) == 1, 
                  n_distinct({{outcome_col}}) == 1 ))   %>%
               dplyr::ungroup(.) %>%
               dplyr::group_split(grp, .keep = FALSE)  
    
    
    
    }
    

    -测试

    > foo2(h, study, group, outcome)
    <list_of<
      tbl_df<
        study  : character
        group  : integer
        outcome: integer
      >
    >[4]>
    [[1]]
    # A tibble: 2 x 3
      study group outcome
      <chr> <int>   <int>
    1 c         1       2
    2 c         2       3
    
    [[2]]
    # A tibble: 2 x 3
      study group outcome
      <chr> <int>   <int>
    1 b         1       1
    2 b         2       1
    
    [[3]]
    # A tibble: 2 x 3
      study group outcome
      <chr> <int>   <int>
    1 a         1       1
    2 a         1       2
    
    [[4]]
    # A tibble: 3 x 3
      study group outcome
      <chr> <int>   <int>
    1 d         1       1
    2 d         1       1
    3 e         1       1
    

    【讨论】:

    • 一定会调查的
    • @rnorouzian 第二部分很简单。您可以在group_by 之前添加select(-time)
    • @rnorouzian 关于第一部分,group_by 也可以在循环之前完成,但 filter 条件不同
    • @rnorouzian 是的,这些已更改为单个 group_split
    • @rnorouzian 是的,这是可能的。你能发布一个新问题吗?谢谢
    猜你喜欢
    • 2021-10-04
    • 2021-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-27
    • 2018-12-22
    • 1970-01-01
    相关资源
    最近更新 更多