使用 ggplot2 在多个日期按工作日和小时绘制平均观察计数

Plotting average observation counts by weekday and hour across multiple dates using ggplot2

我有一个数据框,其中每个观察表示都是我使用 OpenCV 计算的现实世界中的一个对象。经过一些突变并使用 tidyverse 和 lubridate 我的数据框看起来像这样:

> head(odcCountsRoadUsers)
       frameId objectClass dayOfWeek ymdhms              hourOfDay
  1    1133    car         1         2021-12-05 13:45:25 13
  2    1159    car         1         2021-12-05 13:45:26 13
  3    1243    car         1         2021-12-05 13:45:31 13
  4    1280    person      1         2021-12-05 13:45:33 13
  5    1305    bus         1         2021-12-05 13:45:34 13
  6    1812    person      1         2021-12-05 13:46:03 13

我有多天的数据,还包含同一 dayOfWeek 的多个计数。我想要做的是为一周中的每一天(总共 7 个)创建一个直方图,其中包含一天中每个小时的观察次数。结果应类似于此(一周中每天一个直方图):

我的问题是:

  1. 我如何使用 ggplot2 以便它使用 POSIXct ymdhms 作为 x 轴,对于 y 轴通过 hourOfDay(或直接使用 ymdhms 如果可能的话)并按 dayOfWeek?
  2. 过滤
  3. 因为我有好几天的记录,所以我只想要 dayOfWeek 的平均值,而不是简单地将不同日期的所有观察值的计数加在一起。我怎样才能有效地做到这一点?在绘图之前为此创建一个单独的数据框是否有意义,或者可以使用 ggplot2 轻松完成?

关于 objectClass 有机会 separate/group 的额外问题,但这两个是我自己似乎无法弄清楚的最紧迫的问题。

source data is available on GitHub 如果有帮助的话。

你可以总结一下,例如使用 dplyr 包在给定小时内的所有星期一。在求和之后,x 轴只是一个从 0 到 23 的数字,它不再是表示特定、明确时间点的 POSIXct 类型。

library(tidyverse)
library(lubridate)
#> 
#> Attaching package: 'lubridate'
#> The following objects are masked from 'package:base':
#> 
#>     date, intersect, setdiff, union

data <-
  "https://raw.githubusercontent.com/yauh/opendatacam-statistics/main/input/counterData-2022-01-23-61ed51ecae46bd0088feb8f5.csv" %>%
  read_csv(col_names = FALSE) %>%
  transmute(
    frameId = X1,
    objectClass = X4,
    time = X2
  )
#> 
#> ── Column specification ────────────────────────────────────────────────────────
#> cols(
#>   X1 = col_double(),
#>   X2 = col_datetime(format = ""),
#>   X3 = col_character(),
#>   X4 = col_character(),
#>   X5 = col_double(),
#>   X6 = col_double(),
#>   X7 = col_character(),
#>   X8 = col_double()
#> )
data
#> # A tibble: 77,966 × 3
#>    frameId objectClass time               
#>      <dbl> <chr>       <dttm>             
#>  1    6369 person      2022-01-23 13:02:37
#>  2    6457 car         2022-01-23 13:02:42
#>  3    6494 car         2022-01-23 13:02:45
#>  4    6583 car         2022-01-23 13:02:51
#>  5    6587 car         2022-01-23 13:02:51
#>  6    6767 car         2022-01-23 13:03:03
#>  7    6926 car         2022-01-23 13:03:14
#>  8    7201 car         2022-01-23 13:03:32
#>  9    7237 car         2022-01-23 13:03:35
#> 10    7409 car         2022-01-23 13:03:46
#> # … with 77,956 more rows

aggregated_data <-
  data %>%
  mutate(
    weekday = wday(time, label = TRUE),
    hour = hour(time),
    date = date(time)
  ) %>%
  count(weekday, date, hour) %>%
  # average e.g over all mondays
  group_by(weekday, hour) %>%
  summarise(n = mean(n))
#> `summarise()` has grouped output by 'weekday'. You can override using the
#> `.groups` argument.
aggregated_data
#> # A tibble: 168 × 3
#> # Groups:   weekday [7]
#>    weekday  hour     n
#>    <ord>   <int> <dbl>
#>  1 Sun         0    29
#>  2 Sun         1    17
#>  3 Sun         2    17
#>  4 Sun         3    13
#>  5 Sun         4    44
#>  6 Sun         5    29
#>  7 Sun         6    47
#>  8 Sun         7   103
#>  9 Sun         8   245
#> 10 Sun         9   362
#> # … with 158 more rows

aggregated_data %>%
  ggplot(aes(hour, n)) +
  geom_col() +
  facet_wrap(~weekday)

reprex package (v2.0.0)

于 2022-05-20 创建

如果您想比较每个工作日的差异,将它们绘制在一起也是个好主意:

aggregated_data %>%
  ggplot(aes(hour, n, color = weekday)) +
  geom_line()

添加对象 class 作为 group_by 的参数允许我们进行额外的分层:

aggregated_data2 <-
  data %>%
  mutate(
    weekday = wday(time, label = TRUE),
    hour = hour(time),
    date = date(time)
  ) %>%
  count(objectClass, weekday, date, hour) %>%
  # average e.g over all mondays for each object class
  group_by(objectClass, weekday, hour) %>%
  summarise(n = mean(n))

aggregated_data2 %>%
  ggplot(aes(hour, n, color = objectClass)) +
  geom_line() +
  facet_wrap(~weekday, scales = "free")