R 的 move 包中如何按 timeLag 筛选 MoveStack 的轨迹片段?
可以先按个体计算时间间隔,再将超过 300 分钟的片段映射到 dBMvarianceStack 的 @interest,把对应位置设为 FALSE。这样可以保留 Stack 对象,并排除这些片段,无需调用 thinTrackTime()。
这里改变的是片段是否参与后续 dBBMM 计算,定位点仍保留在对象中。@interest 的这一用途见 move 包使用指南。
为什么单条轨迹的写法会报错?
timeLag() 对单条轨迹返回数值向量,对 MoveStack 则返回按个体分组的列表,不能直接对整个返回值执行 > 300。另外,一条包含 n 个定位点的轨迹只有 n − 1 个时间间隔。timeLag 文档说明了这两种返回结构。
仅用 unlist() 展开列表也不够。每条轨迹的间隔数都比定位点数少一个,直接连接后作为全局索引,可能使后续个体的位置错位。
按个体修改 interest
建议直接根据 dbbv 内的轨迹计算间隔,避免依赖它与原始 leroyWithGap 完全相同。方差估计过程中可能省略过短的轨迹,相关行为可见 brownian.motion.variance.dyn 源码。
下面的代码假设 dbbv 是已成功生成、结构有效的 dBMvarianceStack:
library(move)
# 保留原对象,修改副本
filtered <- dbbv
# dBMvarianceStack 继承了轨迹 Stack 的结构
lags_by_id <- timeLag(filtered, units = "mins")
ids <- as.character(trackId(filtered))
stopifnot(length(filtered@interest) == length(ids))
for (id in unique(ids)) {
rows <- which(ids == id)
dt <- lags_by_id[[id]]
if (is.null(dt) || length(dt) != length(rows) - 1L) {
stop("Time-lag alignment failed for track: ", id)
}
# 第 j 个间隔对应该个体第 j 个点到第 j + 1 个点的片段
excluded <- which(dt > 300)
filtered@interest[rows[excluded]] <- FALSE
}
# 后续计算使用 filtered
rows 是该个体在整个 Stack 中的位置,excluded 是该个体内部需要排除的片段编号。rows[excluded] 对应全局 @interest 中要修改的位置。
每条轨迹的最后一个定位点没有后续片段,无需为它补出一个待比较的间隔。代码只将命中的位置设为 FALSE,保留模型原先对其他片段的标记。
其他尝试分别错在哪里?
split(leroyWithGap) 返回列表。要对拆分结果计算间隔,应逐项调用:
tracks <- split(leroyWithGap)
lags_by_id <- lapply(tracks, timeLag, units = "mins")
split() 的返回类型见 move 包 split 文档。上面的结果仍是列表,写回 @interest 时需要按个体映射,不能直接放进原来的下标表达式。
最后一次尝试还有三个独立问题:
split <- split(leroyWithGap))多了一个右括号。"mins"应作为timeLag()的units参数传入。@interest[...]使用一维索引,写成[索引, 条件]会引入多余的下标维度。
筛选前还需要确认什么?
dt > 300 只排除超过 300 分钟的片段;如果也要排除恰好 300 分钟的片段,应改为 dt >= 300。若要排除一组指定间隔,可使用 which(dt %in% excluded_lags),其中 excluded_lags 由实际需求提供,单位同样为分钟。
修改 @interest 不会重新估计已经得到的运动方差。如果希望某些数据从一开始就不参与方差估计,需要另行设计数据预处理,并重新计算方差。
原问题未提供实际对象,以上代码未在该数据上运行。长度检查用于发现索引结构异常;还应结合个体 ID 和时间戳检查具体命中的片段。
备注:内容仅供参考。
