【问题标题】:Counting multiple variables separately in data frame which variable name contains a sequence在数据框中分别计算多个变量,其中变量名包含一个序列
【发布时间】:2020-04-07 20:25:17
【问题描述】:

我有一个巨大的数据框,其中包含多个变量名称,并遵循一个序列。为简化起见,我创建了一个包含 8 个变量的示例,最后 5 个变量遵循列名中的序列: I5min_thresh.118、I5min_thresh.118.5、I5min_thresh.119、I5min_thresh.119.5、I5min_thresh.120)。

变量名中的序列只是一个例子,可以发散,例如变量序列名可以从 60 到 180 步长为 0.1(在本例中为 118 到 120 步长为 0.5 步)。

可重现的数据框:

df<-data.frame(Event=c("yes","yes","yes","no","no","no","no","no","no"),
           mois=c(0.3,0.2,0.2,0.3,0.3,0.3,0.3,0.3,0.2),
           I_float=c(96.0,100.8,96.0,21.6,10.8,10.8,16.8,8.4,16.8),
           Imax.118=c(95.0,105.0,77.0,15.0,5.0,49.7,53.8,51.2,57.8),
           Imax.118.5=c(97.0,90.0,100.0,16.0,15.0,50.2,54.3,51.7,58.3),
           Imax.119=c(98.0,110.0,78.0,51.4,8.0,50.7,54.8,52.2,58.8),
           Imax.119.5=c(99.8,71.0,80.0,51.9,51.2,51.2,55.3,52.7,59.3),
           Imax.120=c(54.6,71.5,79.0,52.4,51.7,51.7,55.8,53.2,59.8))

这是数据框的外观:

我想为每个 Imax 计算以下变量,并将其存储在一个新的数据框中:

  • 如果 Event=yes,I_float >= Imax 的次数,作为变量 TP。
  • 次数 I_float
  • 如果 Event=no,I_float >= Imax 的次数,作为变量 FP。
  • 如果 Event=no,I_float

生成的数据帧应如下所示,其中 Yintercept 等于包含在 Imax 变量中的序列号:

目前我只计算了 1 个变量的 TP、FN、TN 和 FP,假设变量 Imax.118 通过在 r 代码 (Imax.118) 中准确指示变量名称(上一个示例的第一行)。我不能使用手动方法,因为我在真实数据框中有数百个变量,遵循名称序列。

我们将不胜感激。

【问题讨论】:

    标签: r dplyr count


    【解决方案1】:

    使用gather,我们可以使我们的数据变长,只保留原始Imax列的数字和点,然后对我们的Yintercept列进行分组,并对返回TRUE的行数求和为TPFNTNFP 列指定的条件。

    library(tidyverse)
    df %>% 
      gather(Yintercept, val, -Event, -mois, -I_float) %>% 
      mutate(Yintercept = as.numeric(gsub("Imax\\.", "", Yintercept))) %>% 
      group_by(Yintercept) %>% 
      summarise(TP = sum(I_float > val & Event == "yes"),
                FN = sum(I_float < val & Event == "yes"),
                TN = sum(I_float < val & Event == "no"),
                FP = sum(I_float > val & Event == "no"))
    
      Yintercept    TP    FN    TN    FP
           <dbl> <int> <int> <int> <int>
    1       118      2     1     4     2
    2       118.     1     2     5     1
    3       119      1     2     5     1
    4       120.     2     1     6     0
    5       120      3     0     6     0
    

    【讨论】:

    • 非常感谢您的快速响应,我正在为此苦苦挣扎..
    • 欢迎您。顺便说一句,您可以考虑将一个答案标记为已接受。那么所有其他 SO 用户都知道这个问题已经得到充分回答。另见:stackoverflow.com/help/someone-answers
    • 嗨@Lennyy,现在我正在尝试从更复杂的变量名中提取字符串。在我使用 Imax.n 之前(其中 n 是我们在结果数据框中称为 Yintercept 的数字)。现在我正在使用变量模式 I5min_thresh_m_n,例如 I5min_thresh_-140_80)。如果我创建一个字符变量 string
    • 我不明白我在语法上做错了什么。此外,是否可以提取 m 和 n 值并将其作为 2 个变量 m 和 n 存储在结果数据框中?对于 Imax_thresh_-140_80,期望结果将是 m=-140 和 n=80,然后是汇总值 TP、FN、TN、FP)?)。谢谢@Lennyy
    • 我尝试将gsub函数写成gsub("^(?:[^_]+_){2}(.+?)","",string)的形式,结果是“140_80”(没有-140_80)。无论如何,当我将 gsub("Imax\\.", "", Yintercept) 替换为 gsub("^(?:[^_]+_){2}(.+?)","",Yintercept) 时,结果是一样的(只有 1 个 Yintercept 值为 NA 的观察值,以及强制警告引入的 NAs)
    【解决方案2】:

    一种方法是使用最新版本的tidyr 提供的pivot_longer 来输入长格式。

    然后,使用case_when 进行比较并确定每行的真/假阳性/阴性。

    通过Yinterceptoutcome汇总后,可以使用pivot_wider创建最终结果。

    df %>%
      pivot_longer(cols = starts_with("Imax"), names_to = "Yintercept", names_pattern = "^Imax.(\\d.+)",
                   names_ptypes = list(Yintercept = double())) %>%
      mutate(outcome = case_when((I_float >= value) & (Event == "yes") ~ "TP",
                                 (I_float < value) & (Event == "yes") ~ "FN",
                                 (I_float >= value) & (Event == "no") ~ "FP",
                                 (I_float < value) & (Event == "no") ~ "TN")) %>%
      group_by(Yintercept, outcome) %>%
      summarise(count = n()) %>%
      pivot_wider(id_cols = Yintercept, names_from = "outcome", values_from = "count", values_fill = list(count = 0))
    

    输出

    # A tibble: 5 x 5
    # Groups:   Yintercept [5]
      Yintercept    FN    FP    TN    TP
           <dbl> <int> <int> <int> <int>
    1      118       1     2     4     2
    2      118.5     2     1     5     1
    3      119       2     1     5     1
    4      119.5     1     0     6     2
    5      120       0     0     6     3
    

    【讨论】:

    • 谢谢!是否可以在 Yintercept 的输出中替换 Imax?
    • @RaülOo 是的,已更改为 Yintercept - 请参阅编辑后的答案。
    • 感谢您的代码,我将保存这两个答案以备将来使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 2022-01-12
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多