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

如何调整R代码筛选每日最接近午夜的GPS点位

问题描述

我有一批包含日期时间信息的夜间(16:00-次日09:00)GPS点位数据,已将跨午夜的点位统一标记为首个夜间的NightDate,数据包含多个个体ID,且每晚有多条记录。需要按ID和NightDate分组,筛选出每组中最接近午夜的单条点位。

数据格式(含ID列)

NightDatetimeofdaytimeNightDateTime
2019-03-2219.4719:28:0022/03/2019 19:28:00
2019-03-2221.8821:53:0022/03/2019 21:53:00
2019-03-222.7702:46:0022/03/2019 02:46:00
2019-03-2320.5320:32:0023/03/2019 20:32:00
2019-03-2323.0723:04:0023/03/2019 23:04:00
2019-03-231.6701:40:0023/03/2019 01:40:00
2019-03-234.2804:17:0023/03/2019 04:17:00
2019-03-2419.5719:34:0024/03/2019 19:34:00
2019-03-2423.3723:22:0024/03/2019 23:22:00
2019-03-242.0502:03:0024/03/2019 02:03:00
2019-03-244.804:48:0024/03/2019 04:48:00

尝试的代码及问题

最初尝试用timeofday计算与0点的距离,但只保留了凌晨数据,忽略了23点左右接近午夜的记录:

Night <- read.csv("night_redate.csv")

Night.filter <- Night %>% 
  group_by(ID, NightDate) %>% 
  slice(which.min(abs(timeofday - 0)))

write.csv(Night.filter, "filtered_night.csv", row.names = FALSE)

也曾尝试用标准日期时间处理,但筛选逻辑有误:

# Remove rows with NA in 'NightDate' column and group by ID and NightDateTime
Night.edit <- Night %>%
  filter(!is.na(DateTime)) %>%
  group_by(ID, NightDateTime) %>%
  mutate(
    # Convert NightDateTime to Date
    night_date = as.Date(NightDateTime),
    
    # Create Midnight Time
    midnight_time = as.POSIXct(paste(night_date, "00:00:00")),
    
    # Calculate Time Difference
    time_diff = difftime(midnight_time, NightDateTime),
    
    # Take Absolute Value
    time_diff_absolute = abs(as.numeric(time_diff))
  ) %>%
  # Filter for the observation closest to midnight
  filter(time_diff_absolute == min(time_diff_absolute))

需要调整代码,让23:00和01:00这类时间都被纳入接近午夜的考量范围。


解决方案

方法1:修正timeofday的距离计算逻辑

问题出在直接用abs(timeofday - 0)计算距离,23点左右的timeofday值(如23.07)与0的距离是23.07,但实际上它到午夜的距离只有约0.93小时。正确的计算应该是:对于timeofday >= 16的时段(夜间前半段),计算到24点的距离;对于timeofday < 9的时段(夜间后半段,次日凌晨),计算到0点的距离,然后取两者中的最小值对应的记录。

修正后的代码:

library(dplyr)

Night <- read.csv("night_redate.csv")

Night.filter <- Night %>% 
  group_by(ID, NightDate) %>% 
  mutate(
    # 计算到午夜的小时数距离
    midnight_dist = case_when(
      timeofday >= 16 ~ 24 - timeofday,  # 23:04到24:00的距离是0.93小时
      timeofday < 9 ~ timeofday          # 02:46到00:00的距离是2.77小时
    )
  ) %>% 
  slice(which.min(midnight_dist)) %>% 
  select(-midnight_dist)  # 移除临时计算列

write.csv(Night.filter, "filtered_night.csv", row.names = FALSE)

方法2:使用标准日期时间计算(推荐)

利用NightDateTime转换成POSIXct格式,结合NightDate确定对应的午夜时间(即NightDate的次日0点),然后计算每条记录到该午夜的时间差绝对值,取最小值对应的记录。

正确的代码:

library(dplyr)
library(lubridate)

Night <- read.csv("night_redate.csv")

# 先转换NightDateTime为标准日期时间格式,注意匹配你的日期格式
Night <- Night %>% 
  mutate(NightDateTime = dmy_hms(NightDateTime))  # 根据你的数据格式调整,这里是日/月/年 时分秒

Night.filter <- Night %>% 
  group_by(ID, NightDate) %>% 
  mutate(
    # 确定当前NightDate对应的午夜时间:NightDate的次日0点
    midnight_time = as.POSIXct(paste(as.Date(NightDate) + 1, "00:00:00")),
    # 计算到午夜的时间差绝对值(单位:秒)
    time_diff_abs = abs(as.numeric(difftime(midnight_time, NightDateTime, units = "secs")))
  ) %>% 
  slice(which.min(time_diff_abs)) %>% 
  select(-midnight_time, -time_diff_abs)

write.csv(Night.filter, "filtered_night.csv", row.names = FALSE)

说明:

  • 用lubridate的dmy_hms函数可以更便捷地转换日期时间格式,避免手动拼接出错。
  • 因为NightDate是跨午夜数据的首个夜间日期,对应的午夜是NightDate + 1的0点(比如NightDate为2019-03-22,对应的午夜是2019-03-23 00:00:00),这样不管是22日23点还是23日凌晨的记录,计算到这个午夜的时间差都是正确的。

内容的提问来源于stack exchange,提问作者CjC

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 02:39:51