我有一个带时间戳的动物轨迹,并希望 快速 逐步走过这条轨迹,同时向后看一个给定的时间间隔,以确定动物何时与其相交自己的路。
有关如何对以下内容进行矢量化/并行化的建议将非常感谢!
输入数据是100000 * 6矩阵'traj',其中每行代表一条直线段(在轨迹内),由两个连续的时间戳坐标(X1,Y1,T1和X2)构成, Y2,T2):
X1 <- runif(11)
Y1 <- runif(11)
T1 <- c(0.0, 0.5, 2.0, 3.5, 7.0, 7.5, 8.0, 12.0, 12.5, 13.0, 13.5)
X2 <- X1[2:11]
Y2 <- Y1[2:11]
T2 <- T1[2:11]
traj <- cbind(X1 = X1[1:10], Y1 = Y1[1:10], T1 = T1[1:10], X2, Y2, T2)
我定义了一个函数,它将两个带时间戳的坐标转换为psp
线段(spatstat
),然后使用crossing.psp
(spatstat
)测试是否该段与另一个线段相交。如果是,则该函数写入两个段之间的时间差:
INTERSECTS <- function(x)
{
PastSeg <- psp(x["X1"], x["Y1"], x["X2"], x["Y2"], window = windy, marks = x["T1"] , check = F) ## A single line-segment, in which marks give times associated with the 2 coordinate pairs that define the segment
Crossing <- crossing.psp(NowSeg,PastSeg) ## Test if the 2 segments (PastSeg & NowSeg) intersect
if (Crossing$n > 0)
{ ## print(paste("Crossing at ",x["T1"] ))
out <- cbind( NowSeg$marks, x["T1"], ## Get the time of the current trajectory segment
NowSeg$marks - x["T1"], ## Time elapsed between current segment, and past segment
Crossing$x, Crossing$y)
write.table(out, file = "Crossings.txt", append = T, row.names = F, col.names = F)
plot(Crossing, add = T)
}
}
最后,我逐步通过'traj'步骤。在每个步骤t,我考虑轨迹(t-*WINDOW*):(t-1)
的前一部分,称为过去,在其中应用 INTERSECTS :
Window <- 3
library(spatstat)
windy <- owin()
plot(windy,main="")
points(traj[,"X1"],traj[,"Y1"],type="l")
for(FR in 3: nrow(traj))
{
## Define the current trajectory segment
NowSeg <- psp(traj[FR,"X1"], traj[FR,"Y1"],
traj[FR,"X2"], traj[FR,"Y2"],
marks=traj[FR,"T1"], check=F, window=windy) ## The mark gives the time-stamp
## Extract coords up to WINDOW seconds in the past
Past <- traj [traj[,"T1"] < traj[FR-1,"T1"] & traj[,"T1"] > (traj[FR,"T1"]-WINDOW),]
## apply function over rows of Past, to successively test if each trajectory segment in PAST intersects with NowSeg
if (!is.null(dim(Past))) { apply(Past, 1, INTERSECTS) }
}##FR
我试图用 traj 的行替换这个循环,但没有成功,因为过去需要索引到一个行块,而不仅仅是单排。
答案 0 :(得分:1)
这只是一个部分答案,在SO中不受欢迎,但是因为你问了几乎一天......
一种方法是使用包SpatialLines
将您的轨迹转换为sp
对象,然后使用包gIntersects(...)
中的rgeos
来计算轨迹的所有交点本身。这产生逻辑n×n矩阵M
,其中M[i,j] = TRUE
如果i th 段与j th 段相交。但有三个问题:
首先,每个线段都与自身相交,因此所有对角线元素都是TRUE
;我们必须将它们设置为FALSE
。其次,如果j>i
我们检测到一个段和一个未来路径之间的交叉点,那么我们必须将矩阵的下三角形设置为FALSE
。第三,根据定义,每个线段j
与以下线段j+1
相交,因为它们有一个共同点。因此,我们必须将元素[j,j+1]
设置为FALSE
。
n <- 10
set.seed(123)
X1 <- runif(n+1); Y1 <- runif(n+1)
T1 <- c(0.0,0.5,2.0,3.5,7.0,7.5,8.0,12.0,12.5,13.0,13.5)
# T1 <- 1:(n+1)
traj <- cbind(X1=X1[1:n],Y1=Y1[1:n],T1=T1[1:n],
X2=X1[-1],Y2=Y1[-1],T2=T1[-1])
library(sp)
library(rgeos)
sp.lines <- SpatialLines(sapply(1:nrow(traj),
function(i)Lines(Line(rbind(traj[i,1:2],traj[i,4:5])),
ID=i)))
M <- gIntersects(sp.lines,sp.lines,byid=TRUE)
diag(M) <- FALSE
M[lower.tri(M)] <- FALSE
M[cbind(1:(nrow(traj)-1),2:nrow(traj))] <- FALSE
apply(M,2,any)
# 1 2 3 4 5 6 7 8 9 10
# FALSE FALSE TRUE FALSE TRUE FALSE TRUE TRUE FALSE TRUE
crossings <- traj[apply(M,2,any),"T1"]
crossings
# [1] 2 7 8 12 13
plot(sp.lines,col=1:n)
points(traj[,1],traj[,2],col="black",pch=c(as.character(1:9),"A"))
现在,对于M
中的每一列,如果行的任何为TRUE
,则会与某个先前的段存在交集。这条线
apply(M,2,any)
# 1 2 3 4 5 6 7 8 9 10
# FALSE FALSE TRUE FALSE TRUE FALSE TRUE TRUE FALSE TRUE
如果该段与现有路径具有交集,则创建具有元素TRUE
的逻辑向量。因此,在示例中,分段3,5,7,8和10具有与至少一个较早分段的交叉点。如果将其与上图进行比较,您将看到交叉发生的位置。
我们可以将此向量用作T1
的{{1}}列的索引,以确定这些交叉点发生的时间。
traj
因此,在这个例子中,有T1 = 2,7,8,12,13的交叉点。
现在这是这种方法的问题:对于你的完整数据集,n~1e5,所以矩阵将有1e10(100亿)个元素。这太大了。即使不是这样,计算n = 1e4的交点需要大约3分钟,并且该过程按比例缩放为O(n 2 ),因此使用完整数据集需要大约5个小时。这比循环快得多,但仍然太慢。
如果片段不太长,例如如果动物在点之间没有走得太远,你可以对点进行采样。例如,
crossings <- traj[apply(M,2,any),"T1"]
crossings
# [1] 2 7 8 12 13
将每隔十行一次,
smpl <- traj[seq(1,nrow(traj),by=10),]
将随机抽取10%的积分。如果多个随机样本产生的交叉时间与均匀间隔样本没有明显差异,那么这就证明了抽样是合理的。