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

如何使用split.zoo从xts对象中划分降水事件

从xts降水数据中高效拆分降水事件

问题描述

需要从连续观测的xts降水深度对象中拆分单个降水事件,用于后续分析。示例数据如下:

datetime <- seq(as.POSIXct("2020-01-01 00:00", tz = "UTC"), 
                by = "1 min", 
                length.out = 1440)

vals <- rep(0, length(datetime))

x <- xts::xts(vals, order.by = datetime)

# 填充随机降水数据
# 事件1
zoo::coredata(x["2020-01-01 00:30/2020-01-01 02:35"]) <- runif(126, min = 0.01, max = 0.2)

# 事件2
zoo::coredata(x["2020-01-01 08:45/2020-01-01 12:50"]) <- runif(246, min = 0.01, max = 0.2)

# 事件3
zoo::coredata(x["2020-01-01 17:15/2020-01-01 17:30"]) <- runif(16, min = 0.01, max = 0.2)
zoo::coredata(x["2020-01-01 18:15/2020-01-01 19:00"]) <- runif(46, min = 0.01, max = 0.2)
zoo::coredata(x["2020-01-01 22:30/2020-01-01 23:00"]) <- runif(31, min = 0.01, max = 0.2)

降水事件划分规则

  • 以第一个大于0的观测值作为事件起始点
  • 若后续4小时内无降水记录,则以最后一个大于0的观测值作为事件结束点
  • 需要生成与x长度一致的分组向量g:降水时段用事件ID(1、2、...)标记,无降水时段标记为0,最终通过split.zoo拆分得到各事件的zoo/xts对象列表

期望结果

# 最终拆分结果的结构示例
split(x, g) |> str()
#> List of 4
#>  $ 0:'zoo' series from 2020-01-01 to 2020-01-01 23:59:00
#>   Data: num [1:722, 1] 0 0 0 0 0 0 0 0 0 0 ...
#>   Index:  POSIXct[1:722], format: "2020-01-01 00:00:00" "2020-01-01 00:01:00" ...
#>  $ 1:'zoo' series from 2020-01-01 00:30:00 to 2020-01-01 02:35:00
#>   Data: num [1:126, 1] 0.1737 0.0958 0.0491 0.1861 0.1877 ...
#>   Index:  POSIXct[1:126], format: "2020-01-01 00:30:00" "2020-01-01 00:31:00" ...
#>  $ 2:'zoo' series from 2020-01-01 08:45:00 to 2020-01-01 12:50:00
#>   Data: num [1:246, 1] 0.1136 0.1473 0.0433 0.1311 0.1741 ...
#>   Index:  POSIXct[1:246], format: "2020-01-01 08:45:00" "2020-01-01 08:46:00" ...
#>  $ 3:'zoo' series from 2020-01-01 17:15:00 to 2020-01-01 23:00:00
#>   Data: num [1:346, 1] 0.1614 0.0632 0.1216 0.1888 0.0967 ...
#>   Index:  POSIXct[1:346], format: "2020-01-01 17:15:00" "2020-01-01 17:16:00" ...

要求方法高效,能适配不同时间分辨率(如5分钟、小时级)的数十年分钟级数据。

高效解决方案

以下方法采用向量化操作+滚动计算,避免逐行循环,可适配任意时间分辨率,处理大规模数据效率优异:

步骤1:标记降水状态与时间特征

library(xts)
library(zoo)

# 1. 标记所有降水点(>0为TRUE)
is_rain <- coredata(x) > 0

# 2. 获取时间索引向量
dt <- index(x)

# 3. 计算4小时对应的观测点数(自动适配时间分辨率)
window_size <- which.max(dt - dt[1] >= 3600*4)

# 4. 判断每个时间点之后4小时内是否有降水
has_rain_in_4h <- !is.na(rollapplyr(is_rain, width = window_size, 
                                    FUN = any, fill = FALSE))

步骤2:生成事件分组向量g

# 1. 标记事件起始点:当前是降水点,且满足以下任一条件
#    - 前一个点不是降水点
#    - 前一个降水点与当前间隔超过4小时
start_points <- is_rain & (c(FALSE, !is_rain[-length(is_rain)]) | 
                             c(TRUE, diff(dt)[which(is_rain)[-length(which(is_rain))]] > 3600*4))

# 2. 给每个降水点分配事件ID
event_id <- cumsum(start_points)

# 3. 无降水点标记为0,转换为因子类型(split时也可直接用整数向量)
g <- ifelse(is_rain, event_id, 0)
g <- factor(g, levels = c(0, unique(event_id[event_id != 0])))

步骤3:拆分降水事件

# 拆分数据得到各事件的zoo对象列表
event_list <- split(x, g)

# 查看结果结构
str(event_list)

关键特性说明

  • 分辨率适配:无需修改核心逻辑,只要x的时间索引为POSIXct格式,window_size会自动计算4小时对应的观测点数,适配分钟、5分钟、小时等任意分辨率
  • 效率优化:所有操作均为向量化或基于zoo的高效滚动计算,避免循环,可轻松处理数十年的分钟级数据
  • 事件合并逻辑:若两个降水时段间隔小于4小时,会被自动合并为同一个事件,完全符合题目中的划分规则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 06:03:09