【问题标题】:Calculating elapsed “times” in R, where the time depends on a factor在 R 中计算经过的“时间”,其中时间取决于一个因素
【发布时间】:2017-06-30 16:51:06
【问题描述】:

我有一个包含 150,000 + 行的数据框,但这是我想要实现的一个示例:

 TIME_REAL   HR Behaviour
 21:15:00   54  Eupnoea
 21:15:01   107 Eupnoea
 21:15:02   118 Eupnoea
 21:15:03   75  Eupnoea
 21:15:04   94  Eupnoea
 21:15:05   57  Eupnoea
 21:15:06   106 Eupnoea
 21:15:07   121 Eupnoea
 21:15:08   104 Eupnoea
 21:15:09   73  Eupnoea
 21:15:10   114 Apnoea
 21:15:11   108 Apnoea
 21:15:12   121 Apnoea
 21:15:13   117 Apnoea
 21:15:14   110 Apnoea
 21:15:15   38  Eupnoea
 21:15:16   120 Eupnoea
 21:15:17   118 Eupnoea
 21:15:18   82  Eupnoea
 21:15:19   107 Eupnoea
 21:15:20   44  Apnoea

我正在尝试计算行为事件(因素)的持续时间 - 所以第一个 eupnoea 事件将是 9 秒长,然后是 4 秒的呼吸暂停事件等。理想情况下,我希望每个表或列都有一个单独的表或列事件发生的时间和行为事件的持续时间。我曾尝试使用 dplyr 包,但没有任何成功。我还想计算每次行为事件发生时的平均 HR...在 R 中是否有这样做的??

提前谢谢你!

【问题讨论】:

  • 您能否举例说明输出应该是什么样的?您还可以包含您尝试失败的代码。

标签: r time dplyr


【解决方案1】:

您可以尝试以下方法:

dff$TIME_REAL <- as.POSIXct(strptime(dff$TIME_REAL, '%H:%M:%S'))

make_splitter <- function(col_vals) {
  rle_lengths <- rle(as.character(col_vals))$lengths
  rep(1:length(rle_lengths), rle_lengths)
}

dff %>%
group_by(splitter = make_splitter(Behaviour), Behaviour) %>%
summarise(Average_HR = mean(HR),
        Start_Time = strftime(head(TIME_REAL, 1), '%H:%M:%S'),
        End_Time = strftime(tail(TIME_REAL, 1), '%H:%M:%S'),
        Duration = difftime(tail(TIME_REAL, 1), head(TIME_REAL, 1)))

首先,创建一个函数来帮助定义您希望如何拆分数据框。在这里,我使用rle 函数和一些复制来获得理想的列。

假设您当前的数据帧名为dff,您可以将TIME_REAL 列强制转换为as.POSIXct 对象,然后才能继续对其进行任何计算。随后,您可以使用dplyr将拆分器列和Behavior列分组,然后使用summarise函数得到HR的平均值和时间差。

应该让步:

  Behaviour Average_HR Start_Time End_Time Duration
     <fctr>      <dbl>      <chr>    <chr>   <time>
1   Eupnoea       90.9   21:15:00 21:15:09   9 secs
2    Apnoea      114.0   21:15:10 21:15:14   4 secs
3   Eupnoea       93.0   21:15:15 21:15:19   4 secs
4    Apnoea       44.0   21:15:20 21:15:20   0 secs

我希望这会有所帮助。

【讨论】:

  • 感谢您的帮助!不幸的是,我无法让它发挥作用,因为行为是因素....错误消息“最大对因素没有意义”。我无法将它们转换为其他任何东西 - 你知道解决这个问题的方法吗?
  • @dphil,错误来自哪里?当Behavior 列是factor 时,此处的代码可以正常工作。无论哪种方式,您都应该能够在任何 factor 值上临时使用 as.character
  • 我不知道为什么它不起作用,但非常感谢你,在玩过它之后,它完美地工作了。有没有什么方法可以将开始时间和结束时间添加到这个输出中(对不起!!)持续时间很长,但也可能存在昼夜效应,我意识到这很难分辨。
  • 感谢您的帮助!!
【解决方案2】:
library(tidyverse)

tbl <- tribble(
  ~TIME_REAL,   ~HR, ~Behaviour,
  "21:15:00",   54,  "Eupnoea",
  "21:15:01",   107, "Eupnoea",
  "21:15:02",   118, "Eupnoea",
  "21:15:03",   75,  "Eupnoea",
  "21:15:04",   94,  "Eupnoea",
  "21:15:05",   57,  "Eupnoea",
  "21:15:06",   106, "Eupnoea",
  "21:15:07",   121, "Eupnoea",
  "21:15:08",   104, "Eupnoea",
  "21:15:09",   73,  "Eupnoea",
  "21:15:10",   114, "Apnoea",
  "21:15:11",   108, "Apnoea",
  "21:15:12",   121, "Apnoea",
  "21:15:13",   117, "Apnoea",
  "21:15:14",   110, "Apnoea",
  "21:15:15",   38,  "Eupnoea",
  "21:15:16",   120, "Eupnoea",
  "21:15:17",   118, "Eupnoea",
  "21:15:18",   82,  "Eupnoea",
  "21:15:19",   107, "Eupnoea",
  "21:15:20",   44,  "Apnoea"
)

myle <- rle(tbl$Behaviour)
tbl %>% 
  mutate(code = rep(seq_along(myle$values), myle$lengths)) %>%
  group_by(Behaviour, code) %>%
  summarise(N = n(), mean = mean(HR)) %>% 
  arrange(code)

【讨论】:

    【解决方案3】:

    data.tablerleid 的帮助下,这是使用 dplyr 的方法。我使用rleid,因为它是添加组号的简单方法。我也在使用as.POSIXct将时间列转换为时间对象,这样更容易操作。

    library(dplyr)
    df %>%
      mutate(TIME_REAL=as.POSIXct(TIME_REAL,format="%H:%M:%S"),
               behaviour_number=data.table::rleid(Behaviour))%>%
      group_by(behaviour_number)%>%
      summarise(behaviour=max(Behaviour),elapsed=max(TIME_REAL)-min(TIME_REAL),
                HR_avg=mean(HR,na.rm=TRUE))
    
      behaviour_number behaviour elapsed HR_avg
                 <int>     <chr>  <time>  <dbl>
    1                1   Eupnoea  9 secs   90.9
    2                2    Apnoea  4 secs  114.0
    3                3   Eupnoea  4 secs   93.0
    4                4    Apnoea  0 secs   44.0
    

    数据

    df <- read.table(text="TIME_REAL   HR Behaviour
     21:15:00   54  Eupnoea
                     21:15:01   107 Eupnoea
                     21:15:02   118 Eupnoea
                     21:15:03   75  Eupnoea
                     21:15:04   94  Eupnoea
                     21:15:05   57  Eupnoea
                     21:15:06   106 Eupnoea
                     21:15:07   121 Eupnoea
                     21:15:08   104 Eupnoea
                     21:15:09   73  Eupnoea
                     21:15:10   114 Apnoea
                     21:15:11   108 Apnoea
                     21:15:12   121 Apnoea
                     21:15:13   117 Apnoea
                     21:15:14   110 Apnoea
                     21:15:15   38  Eupnoea
                     21:15:16   120 Eupnoea
                     21:15:17   118 Eupnoea
                     21:15:18   82  Eupnoea
                     21:15:19   107 Eupnoea
                     21:15:20   44  Apnoea",header=TRUE,stringsAsFactors=FALSE)
    

    【讨论】:

      【解决方案4】:

      使用日期时,我建议使用lubridate

      在这里您需要构造一个完整的日期格式才能使用日期。为了这个例子,我们假设今天是今天。

      library(tidyverse)
      try <- tribble(
        ~TIME_REAL, ~Behaviour,
        "21:15:00", "Eupnoea",
        "21:15:03", "Eupnoea",
        "21:15:04", "Eupnoea",
        "21:15:09", "Eupnoea",
        "21:15:10", "Apnoea",
        "21:15:15", "Apnoea",
        "21:15:17", "Apnoea",
        "21:15:18", "Apnoea"
      )
      library(lubridate)
      try %>%
        mutate(TIME_REAL = paste(today(), TIME_REAL)) %>%
        mutate(TIME_REAL = ymd_hms(TIME_REAL)) %>%
        group_by(Behaviour) %>%
        summarize(time = max(TIME_REAL) - min(TIME_REAL))
      
      
      # A tibble: 2 x 2
        Behaviour   time
            <chr> <time>
      1    Apnoea 8 secs
      2   Eupnoea 9 secs
      

      这里的两个mutate 调用将日期转换为ISO8601。然后你可以分组并做基本的数学运算。

      希望对你有帮助

      科林

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-25
        • 2011-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-01
        • 1970-01-01
        相关资源
        最近更新 更多