【问题标题】:Finding cumulative second max per group in R在R中找到每组累积的第二个最大值
【发布时间】:2021-02-08 18:44:20
【问题描述】:

我有一个数据集,我想在其中创建一个新变量,该变量是另一个变量的累积第二大值,我想按组执行此函数。

假设我创建了以下示例数据框:

(df1 <- data.frame(patient = rep(1:5, each=8), visit = rep(1:2,each=4,5), trial = rep(1:4,10), var1 = sample(1:50,20,replace=TRUE)))

这是代表 5 名患者的假数据,每人有 2 次研究访问,每次访问都有 4 次试验并进行测量 (var1)。

> head(df1,n=20)
   patient visit trial var1
1        1     1     1   25
2        1     1     2   23
3        1     1     3   48
4        1     1     4   37
5        1     2     1   41
6        1     2     2   45
7        1     2     3    8
8        1     2     4    9
9        2     1     1   26
10       2     1     2   14
11       2     1     3   41
12       2     1     4   35
13       2     2     1   37
14       2     2     2   30
15       2     2     3   14
16       2     2     4   28
17       3     1     1   34
18       3     1     2   19
19       3     1     3   28
20       3     1     4   10

我想创建一个新变量 cum2ndmax,它是 var1 的累积第二大值,我想将该变量按患者 # 分组并访问 #。

我想出了如何计算累积的第二个最大数字,如下所示:

df1$cum2ndmax <- sapply(seq_along(df1$var1),function(x){sort(df1$var1[seq(x)],decreasing=TRUE)[2]})
df1

但是,这会计算整个数据集的累积第二个最大值,而不是每个组。在安装和加载包 dplyr 后,我尝试使用分组数据计算此变量:

library(dplyr)    
df2 <- df1 %>%
        group_by(patient,visit) %>%
        mutate(cum2ndmax = sapply(seq_along(df1$var1),function(x){sort(df1$var1[seq(x)],decreasing=TRUE)[2]}))

但我收到一个错误:错误:mutate() 输入问题cum2ndmax。 x 输入 cum2ndmax 无法回收到大小 4。

理想情况下,我的结果应该是这样的:

patient visit   trial   var1    cum2ndmax
1   1   1   25  NA
1   1   2   23  23
1   1   3   48  25
1   1   4   37  37
1   2   1   41  NA
1   2   2   45  41
1   2   3   8   41
1   2   4   9   41
2   1   1   26  NA
2   1   2   14  14
2   1   3   41  26
2   1   4   35  35
…   …   …   …   …

任何帮助使其在 R 中工作的帮助将不胜感激!谢谢!

【问题讨论】:

    标签: r


    【解决方案1】:

    dplyrpurrr 选项可以是:

    df1 %>%
     group_by(patient, visit) %>%
     mutate(cum_second_max = map_dbl(.x = seq_along(var1),
                                     ~ ifelse(.x == 1, NA, var1[dense_rank(-var1[1:.x]) == 2])))
    
       patient visit trial  var1 cum_second_max
         <int> <int> <int> <int>          <dbl>
     1       1     1     1    25             NA
     2       1     1     2    23             23
     3       1     1     3    48             25
     4       1     1     4    37             37
     5       1     2     1    41             NA
     6       1     2     2    45             41
     7       1     2     3     8             41
     8       1     2     4     9             41
     9       2     1     1    26             NA
    10       2     1     2    14             14
    11       2     1     3    41             26
    12       2     1     4    35             35
    13       2     2     1    37             NA
    14       2     2     2    30             30
    15       2     2     3    14             30
    16       2     2     4    28             30
    17       3     1     1    34             NA
    18       3     1     2    19             19
    19       3     1     3    28             28
    20       3     1     4    10             28
    

    【讨论】:

      【解决方案2】:

      这是Rcpp 解决方案。

      cum_second_max 是对cummax 的修改,它跟踪第二个最大值。

      library(tidyverse)
      
      Rcpp::cppFunction("
      NumericVector cum_second_max(NumericVector x) {
        double max_value = R_NegInf, max_value2 = NA_REAL;
        NumericVector result(x.length());
      
        for (int i = 0 ; i < x.length() ; ++i) {
          if (x[i] > max_value) {
            max_value2 = max_value;
            max_value = x[i];
          }
          else if (x[i] < max_value && x[i] > max_value2) {
            max_value2 = x[i];
          }
          result[i] = isinf(max_value2) ? NA_REAL : max_value2;
        }
        return result;
      }
      ")
      
      df1 %>%
        group_by(patient, visit) %>%
        mutate(
          c2max = cum_second_max(var1)
        )
      #> # A tibble: 20 x 5
      #> # Groups:   patient, visit [5]
      #>    patient visit trial  var1 c2max
      #>      <dbl> <dbl> <dbl> <dbl> <dbl>
      #>  1       1     1     1    25    NA
      #>  2       1     1     2    23    23
      #>  3       1     1     3    48    25
      #>  4       1     1     4    37    37
      #>  5       1     2     1    41    NA
      #>  6       1     2     2    45    41
      #>  7       1     2     3     8    41
      #>  8       1     2     4     9    41
      #>  9       2     1     1    26    NA
      #> 10       2     1     2    14    14
      #> 11       2     1     3    41    26
      #> 12       2     1     4    35    35
      #> 13       2     2     1    37    NA
      #> 14       2     2     2    30    30
      #> 15       2     2     3    14    30
      #> 16       2     2     4    28    30
      #> 17       3     1     1    34    NA
      #> 18       3     1     2    19    19
      #> 19       3     1     3    28    28
      #> 20       3     1     4    10    28
      

      【讨论】:

        【解决方案3】:

        非常感谢大家!我真的很感激,如果没有你的帮助,我无法解决这个问题!最后,我最终使用了 tmfmnk 建议的类似方法,因为我已经在使用 dplyr。我在 tmkmnk 建议的代码中发现了一个有趣的结果,由于某种原因,它给了我一列只重复第一行编号的值。稍微调整一下将 dense_rank 更改为 order,我得到了我想要的:

        df1 %>%
         group_by(patient, visit) %>%
         mutate(cum_second_max = map_dbl(.x = seq_along(var1),
                                         ~ ifelse(.x == 1, NA, var1[order(-var1[1:.x])[2])))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-04
          • 2022-06-10
          • 1970-01-01
          • 1970-01-01
          • 2021-06-06
          • 1970-01-01
          相关资源
          最近更新 更多