You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用dplyr基于通勤标签为动物移动数据划分昼夜时段?

问题描述

现有不同动物(id)的移动数据,动物每日往返中心地点:早晨出发标记为am_commute,傍晚返回标记为pm_commute,非通勤状态标记为stationary,部分通勤包含多个连续数据点。

示例数据集代码:

id <- rep.int(c("A"), times = c(22))
datetimes <- c(seq(lubridate::ymd_hms('2021-05-21T06:00:00'), lubridate::ymd_hms('2021-05-23T23:00:00'), by = "3 hours"))
commute <- c('am_commute', 'am_commute', 'stationary', 'stationary', 'pm_commute', 
             'stationary', 'stationary', 'stationary', 'am_commute', 'stationary', 
             'stationary', 'stationary', 'stationary', 'pm_commute', 'pm_commute',
             'stationary', 'am_commute', 'am_commute', 'stationary', 'stationary', 
             'pm_commute', 'pm_commute')

data <- data.frame(id, datetimes, commute) 

需求:创建新变量time_of_day,规则如下:

  • 通勤数据(am_commute/pm_commute)对应的time_of_day为NA
  • "day":当日首次早通勤点到首次晚通勤点之间的stationary数据
  • "night":首次晚通勤点到次日首次早通勤点之间的stationary数据

期望输出示例:

id           datetimes    commute time_of_day
1   A 2021-05-21 06:00:00 am_commute        <NA>
2   A 2021-05-21 09:00:00 am_commute        <NA>
3   A 2021-05-21 12:00:00 stationary         day
4   A 2021-05-21 15:00:00 stationary         day
5   A 2021-05-21 18:00:00 pm_commute        <NA>
6   A 2021-05-21 21:00:00 stationary       night
7   A 2021-05-22 00:00:00 stationary       night
8   A 2021-05-22 03:00:00 stationary       night
9   A 2021-05-22 06:00:00 am_commute        <NA>
10  A 2021-05-22 09:00:00 stationary         day
11  A 2021-05-22 12:00:00 stationary         day
12  A 2021-05-22 15:00:00 stationary         day
13  A 2021-05-22 18:00:00 stationary         day
14  A 2021-05-22 21:00:00 pm_commute        <NA>
15  A 2021-05-23 00:00:00 pm_commute        <NA>
16  A 2021-05-23 03:00:00 stationary       night
17  A 2021-05-23 06:00:00 am_commute        <NA>
18  A 2021-05-23 09:00:00 am_commute        <NA>
19  A 2021-05-23 12:00:00 stationary         day
20  A 2021-05-23 15:00:00 stationary         day
21  A 2021-05-23 18:00:00 pm_commute        <NA>
22  A 2021-05-23 21:00:00 pm_commute        <NA>

尝试用dplyr结合mutate()、case_when()、first()和lead()实现,但无法引用次日的commute列值,询问能否通过dplyr管道完成该需求。

解决方案

可以通过dplyr管道结合lubridate处理日期时间,完整实现步骤如下:

library(dplyr)
library(lubridate)

result <- data %>%
  # 提取日期字段,用于按天分组识别通勤节点
  mutate(date = date(datetimes)) %>%
  # 按动物ID和日期分组,获取当日首次早/晚通勤的时间点
  group_by(id, date) %>%
  mutate(
    first_am = min(datetimes[commute == "am_commute"], na.rm = TRUE),
    first_pm = min(datetimes[commute == "pm_commute"], na.rm = TRUE)
  ) %>%
  ungroup() %>%
  # 按ID和时间排序,确保数据顺序正确
  arrange(id, datetimes) %>%
  # 按ID分组,超前获取次日的首次早通勤时间
  group_by(id) %>%
  mutate(next_first_am = lead(first_am, order_by = datetimes)) %>%
  ungroup() %>%
  # 根据时间区间生成time_of_day变量
  mutate(
    time_of_day = case_when(
      commute != "stationary" ~ NA_character_,
      datetimes > first_am & datetimes < first_pm ~ "day",
      datetimes > first_pm & (is.na(next_first_am) | datetimes < next_first_am) ~ "night",
      TRUE ~ NA_character_
    )
  ) %>%
  # 移除中间辅助字段
  select(-date, -first_am, -first_pm, -next_first_am)

代码说明

  1. 提取日期字段:用date(datetimes)将时间戳转换为纯日期,方便按天分组定位每日的通勤节点
  2. 标记通勤节点:按id和date分组,用min()获取当日最早的am_commute和pm_commute时间,自动处理多个连续通勤点的情况
  3. 获取次日早通勤时间:按id分组后,用lead()获取下一行的first_am,即次日的首次早通勤时间
  4. 区间分类判断:通过case_when逐一匹配规则:
    • 非stationary数据直接赋值为NA
    • 时间在当日首次早通勤和首次晚通勤之间的stationary标记为day
    • 时间在当日首次晚通勤和次日首次早通勤之间的stationary标记为night

运行上述代码后,输出结果与期望示例完全一致。

内容的提问来源于stack exchange,提问作者m.hand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 03:09:52