当前位置: 首页 > 知识库问答 >
问题:

计算以小时为单位的日期与以R为单位的每组最接近的条件行之间的差异

钱德元
2023-03-14

我有以下名为df的示例数据帧(下面的< code>dput):

   group                date indicator
1      A 2022-11-01 01:00:00     FALSE
2      A 2022-11-01 03:00:00     FALSE
3      A 2022-11-01 04:00:00      TRUE
4      A 2022-11-01 05:00:00     FALSE
5      A 2022-11-01 06:00:00      TRUE
6      A 2022-11-01 07:00:00     FALSE
7      A 2022-11-01 10:00:00     FALSE
8      A 2022-11-01 12:00:00     FALSE
9      B 2022-11-01 01:00:00     FALSE
10     B 2022-11-01 02:00:00     FALSE
11     B 2022-11-01 03:00:00     FALSE
12     B 2022-11-01 06:00:00      TRUE
13     B 2022-11-01 07:00:00     FALSE
14     B 2022-11-01 08:00:00     FALSE
15     B 2022-11-01 11:00:00      TRUE
16     B 2022-11-01 13:00:00     FALSE

我想用最近的条件行计算日期之间的小时差,这些条件行的每一组都有指示符==TRUE。此外,带有TRUE的行应返回0作为输出。这里可以看到所需的输出df_desired:

   group                date indicator diff_hours
1      A 2022-11-01 01:00:00     FALSE          3
2      A 2022-11-01 03:00:00     FALSE          1
3      A 2022-11-01 04:00:00      TRUE          0
4      A 2022-11-01 05:00:00     FALSE          1
5      A 2022-11-01 06:00:00      TRUE          0
6      A 2022-11-01 07:00:00     FALSE          1
7      A 2022-11-01 10:00:00     FALSE          4
8      A 2022-11-01 12:00:00     FALSE          6
9      B 2022-11-01 01:00:00     FALSE          5
10     B 2022-11-01 02:00:00     FALSE          4
11     B 2022-11-01 03:00:00     FALSE          3
12     B 2022-11-01 06:00:00      TRUE          0
13     B 2022-11-01 07:00:00     FALSE          1
14     B 2022-11-01 08:00:00     FALSE          2
15     B 2022-11-01 11:00:00      TRUE          0
16     B 2022-11-01 13:00:00     FALSE          2

所以我想知道是否有人知道如何计算每组最近的条件行的小时日期之间的差异?

这里dapp的df和df_desired:

df <- structure(list(group = c("A", "A", "A", "A", "A", "A", "A", "A", 
"B", "B", "B", "B", "B", "B", "B", "B"), date = structure(c(1667260800, 
1667268000, 1667271600, 1667275200, 1667278800, 1667282400, 1667293200, 
1667300400, 1667260800, 1667264400, 1667268000, 1667278800, 1667282400, 
1667286000, 1667296800, 1667304000), class = c("POSIXct", "POSIXt"
), tzone = ""), indicator = c(FALSE, FALSE, TRUE, FALSE, TRUE, 
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, 
TRUE, FALSE)), class = "data.frame", row.names = c(NA, -16L))

df_desired <- structure(list(group = c("A", "A", "A", "A", "A", "A", "A", "A", 
"B", "B", "B", "B", "B", "B", "B", "B"), date = structure(c(1667260800, 
1667268000, 1667271600, 1667275200, 1667278800, 1667282400, 1667293200, 
1667300400, 1667260800, 1667264400, 1667268000, 1667278800, 1667282400, 
1667286000, 1667296800, 1667304000), class = c("POSIXct", "POSIXt"
), tzone = ""), indicator = c(FALSE, FALSE, TRUE, FALSE, TRUE, 
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, 
TRUE, FALSE), diff_hours = c(3, 1, 0, 1, 0, 1, 4, 6, 5, 4, 3, 
0, 1, 2, 0, 2)), class = "data.frame", row.names = c(NA, -16L
))

共有3个答案

邹海超
2023-03-14

下面是以前在base R中使用的一些方法:

#Maël answer in base R
by(df, df$group, \(d) transform(
  d, diff_hours = sapply(d$date, \(x) min(abs(x - d$date[d[["indicator"]]])))
  )) |>
  do.call(what = rbind.data.frame)
#>      group                date indicator diff_hours
#> A.1      A 2022-10-31 20:00:00     FALSE          3
#> A.2      A 2022-10-31 22:00:00     FALSE          1
#> A.3      A 2022-10-31 23:00:00      TRUE          0
#> A.4      A 2022-11-01 00:00:00     FALSE          1
#> A.5      A 2022-11-01 01:00:00      TRUE          0
#> A.6      A 2022-11-01 02:00:00     FALSE          1
#> A.7      A 2022-11-01 05:00:00     FALSE          4
#> A.8      A 2022-11-01 07:00:00     FALSE          6
#> B.9      B 2022-10-31 20:00:00     FALSE          5
#> B.10     B 2022-10-31 21:00:00     FALSE          4
#> B.11     B 2022-10-31 22:00:00     FALSE          3
#> B.12     B 2022-11-01 01:00:00      TRUE          0
#> B.13     B 2022-11-01 02:00:00     FALSE          1
#> B.14     B 2022-11-01 03:00:00     FALSE          2
#> B.15     B 2022-11-01 06:00:00      TRUE          0
#> B.16     B 2022-11-01 08:00:00     FALSE          2

#ThomasIsCoding answer in base
transform(df, diff_hours = apply(abs(outer(df$date, df$date[df$indicator], `-`))/3600, 1, min))
#>    group                date indicator diff_hours
#> 1      A 2022-10-31 20:00:00     FALSE          3
#> 2      A 2022-10-31 22:00:00     FALSE          1
#> 3      A 2022-10-31 23:00:00      TRUE          0
#> 4      A 2022-11-01 00:00:00     FALSE          1
#> 5      A 2022-11-01 01:00:00      TRUE          0
#> 6      A 2022-11-01 02:00:00     FALSE          1
#> 7      A 2022-11-01 05:00:00     FALSE          1
#> 8      A 2022-11-01 07:00:00     FALSE          1
#> 9      B 2022-10-31 20:00:00     FALSE          3
#> 10     B 2022-10-31 21:00:00     FALSE          2
#> 11     B 2022-10-31 22:00:00     FALSE          1
#> 12     B 2022-11-01 01:00:00      TRUE          0
#> 13     B 2022-11-01 02:00:00     FALSE          1
#> 14     B 2022-11-01 03:00:00     FALSE          2
#> 15     B 2022-11-01 06:00:00      TRUE          0
#> 16     B 2022-11-01 08:00:00     FALSE          2
奚曦哲
2023-03-14

你可以像下面这样尝试data.table(应该有比我的更有效的选项)

  • 使用 findIntervalroll = “nearest”
setDT(df)[
  ,
  diff_hours := abs(
    difftime(date,
      date[indicator][pmax(1, findInterval(date, date[indicator]))],
      units = "hours"
    )
  ),
  group
][]

setDT(df)[
  ,
  diffhours := abs(
    difftime(date,
      .SD[indicator][.SD,
        date,
        by = group,
        on = "date",
        roll = "nearest",
        mult = "first"
      ][, date],
      units = "hours"
    )
  )
][]

这给了

    group                date indicator diff_hours
 1:     A 2022-11-01 01:00:00     FALSE    3 hours
 2:     A 2022-11-01 03:00:00     FALSE    1 hours
 3:     A 2022-11-01 04:00:00      TRUE    0 hours
 4:     A 2022-11-01 05:00:00     FALSE    1 hours
 5:     A 2022-11-01 06:00:00      TRUE    0 hours
 6:     A 2022-11-01 07:00:00     FALSE    1 hours
 7:     A 2022-11-01 10:00:00     FALSE    4 hours
 8:     A 2022-11-01 12:00:00     FALSE    6 hours
 9:     B 2022-11-01 01:00:00     FALSE    5 hours
10:     B 2022-11-01 02:00:00     FALSE    4 hours
11:     B 2022-11-01 03:00:00     FALSE    3 hours
12:     B 2022-11-01 06:00:00      TRUE    0 hours
13:     B 2022-11-01 07:00:00     FALSE    1 hours
14:     B 2022-11-01 08:00:00     FALSE    2 hours
15:     B 2022-11-01 11:00:00      TRUE    0 hours
16:     B 2022-11-01 13:00:00     FALSE    2 hours
  • 使用外部(由于使用了apply,因此效率不高)
setDT(df)[
  ,
  diff_hours := apply(abs(outer(date, date[indicator], `-`)), 1, min) / 3600,
  group
][]

你会看到的

    group                date indicator diff_hours
 1:     A 2022-11-01 01:00:00     FALSE          3
 2:     A 2022-11-01 03:00:00     FALSE          1
 3:     A 2022-11-01 04:00:00      TRUE          0
 4:     A 2022-11-01 05:00:00     FALSE          1
 5:     A 2022-11-01 06:00:00      TRUE          0
 6:     A 2022-11-01 07:00:00     FALSE          1
 7:     A 2022-11-01 10:00:00     FALSE          4
 8:     A 2022-11-01 12:00:00     FALSE          6
 9:     B 2022-11-01 01:00:00     FALSE          5
10:     B 2022-11-01 02:00:00     FALSE          4
11:     B 2022-11-01 03:00:00     FALSE          3
12:     B 2022-11-01 06:00:00      TRUE          0
13:     B 2022-11-01 07:00:00     FALSE          1
14:     B 2022-11-01 08:00:00     FALSE          2
15:     B 2022-11-01 11:00:00      TRUE          0
16:     B 2022-11-01 13:00:00     FALSE          2
朱起运
2023-03-14

使用< code>map_dbl:

library(dplyr)
library(purrr)
df %>% 
  group_by(group) %>% 
  mutate(diff_hours = map_dbl(date, ~ min(abs(.x - date[indicator]))))

输出

# A tibble: 16 × 4
# Groups:   group [2]
   group date                indicator diff_hours
   <chr> <dttm>              <lgl>          <dbl>
 1 A     2022-11-01 01:00:00 FALSE              3
 2 A     2022-11-01 03:00:00 FALSE              1
 3 A     2022-11-01 04:00:00 TRUE               0
 4 A     2022-11-01 05:00:00 FALSE              1
 5 A     2022-11-01 06:00:00 TRUE               0
 6 A     2022-11-01 07:00:00 FALSE              1
 7 A     2022-11-01 10:00:00 FALSE              4
 8 A     2022-11-01 12:00:00 FALSE              6
 9 B     2022-11-01 01:00:00 FALSE              5
10 B     2022-11-01 02:00:00 FALSE              4
11 B     2022-11-01 03:00:00 FALSE              3
12 B     2022-11-01 06:00:00 TRUE               0
13 B     2022-11-01 07:00:00 FALSE              1
14 B     2022-11-01 08:00:00 FALSE              2
15 B     2022-11-01 11:00:00 TRUE               0
16 B     2022-11-01 13:00:00 FALSE              2

如果想保持原始差异(不是绝对的):

df %>% 
  group_by(group) %>% 
  mutate(diff_hours = map_dbl(date, ~ (.x - date[indicator])[which.min(abs(.x - date[indicator]))]))
 类似资料:
  • 问题内容: 大家好, 在我的项目中,我需要计算 两个日期之间以秒为单位 的 时差 : 例如 : 然后我应该得到 86400秒, 即24小时。 类似地 它应该返回 60秒 。 我读了很多问题,其中 2分钟字段*之间的区别是 11:50:01和12:10:57 *** 问题答案: $timeFirst = strtotime(‘2011-05-12 18:20:20’); $timeSecond =

  • 问题内容: 我想计算年份和月份中两个datetime.date()日期之间的差异。 例如; 所需结果: 谢谢。 问题答案: 如果您能够安装出色的dateutil软件包,则可以执行以下操作:

  • 问题内容: 我需要获取两个日期之间的分钟数。我知道Joda是最适合使用的,但这是针对Android项目的,因此,我更喜欢使用一些外部库,并且我正在构建的应用程序不需要计算得很精确。 但是,我正在使用的代码似乎无法正常工作。我正在尝试获取“ 11/21/2011 7:00:00 AM”和“ 11/21/2011 1:00:00 PM”之间的分钟数(应该为360分钟),但是代码我’m using返回0

  • 问题内容: 我试图在几秒钟之内得到两个日期之间的差异。逻辑将是这样的: 设置一个初始日期,即现在; 设置最终日期,该日期将是初始日期加上将来的秒数(例如,假设15) 得到这两者之间的差(秒数) 之所以使用日期来做,是因为最终日期/时间取决于其他一些变量,并且永远不一样(取决于用户执行操作的速度),并且我还存储其他日期的初始日期。 我一直在尝试这样的事情: 问题是我永远都不会得到正确的区别。我尝试过

  • 我试图以天计算两个日期之间的差异。然而,当两个日期在不同的月份时,前一个月的日子被丢弃。 例如,如果开始日期是3月31日,结束日期是4月1日,则差异为0。 如果两天在同一个月,它工作正常。 提前感谢您的支持。 更新:我想到了如何修复它。除了选择的日期是一个月的最后一天,一切都按预期进行。可以在下面找到一个实时演示: 这里的演示 例如,开始日期:3月19日,结束日期:3月21日。差2天。 但当选择的

  • 问题内容: 我通过传递ipAddress来对方法进行调用,它会返回ipAddress的位置,例如国家/地区,城市等。因此,我试图查看每个调用花费的时间。因此,我在调用方法之前设置了start_time,在调用之后设置了end_time。 所以有时候我得到的差为0 。并且resp包含有效的响应。 因此,这意味着有时需要0毫秒才能恢复响应。任何建议将不胜感激。 问题答案: 试试这个