我有2个向量:
set.seed(1)
x1 = rnorm(100,0,1)
x2 = rnorm(100,1,1)
我想将这些绘制为线条,然后找到线条的交点,如果有多个交叉点,那么我想找到它们中的每一个。
我遇到了类似的问题,并尝试使用spatstat
解决此问题,但我无法将包含这两个矢量值的合并数据框转换为psp object
。
答案 0 :(得分:16)
如果您确实只有两个随机的数字向量,您可以使用一种非常简单的技术来获得两者的交集。只需查找x1
高于x2
的所有点,然后在下一点下方,或反之亦然。这些是交叉点。然后只需使用相应的斜率来找到该段的截距。
set.seed(1)
x1=rnorm(100,0,1)
x2=rnorm(100,1,1)
# Find points where x1 is above x2.
above<-x1>x2
# Points always intersect when above=TRUE, then FALSE or reverse
intersect.points<-which(diff(above)!=0)
# Find the slopes for each line segment.
x1.slopes<-x1[intersect.points+1]-x1[intersect.points]
x2.slopes<-x2[intersect.points+1]-x2[intersect.points]
# Find the intersection for each segment.
x.points<-intersect.points + ((x2[intersect.points] - x1[intersect.points]) / (x1.slopes-x2.slopes))
y.points<-x1[intersect.points] + (x1.slopes*(x.points-intersect.points))
# Plot.
plot(x1,type='l')
lines(x2,type='l',col='red')
points(x.points,y.points,col='blue')
答案 1 :(得分:5)
这是一个替代的细分 - 段交叉代码,
# segment-segment intersection code
# http://paulbourke.net/geometry/pointlineplane/
ssi <- function(x1, x2, x3, x4, y1, y2, y3, y4){
denom <- ((y4 - y3)*(x2 - x1) - (x4 - x3)*(y2 - y1))
denom[abs(denom) < 1e-10] <- NA # parallel lines
ua <- ((x4 - x3)*(y1 - y3) - (y4 - y3)*(x1 - x3)) / denom
ub <- ((x2 - x1)*(y1 - y3) - (y2 - y1)*(x1 - x3)) / denom
x <- x1 + ua * (x2 - x1)
y <- y1 + ua * (y2 - y1)
inside <- (ua >= 0) & (ua <= 1) & (ub >= 0) & (ub <= 1)
data.frame(x = ifelse(inside, x, NA),
y = ifelse(inside, y, NA))
}
# do it with two polylines (xy dataframes)
ssi_polyline <- function(l1, l2){
n1 <- nrow(l1)
n2 <- nrow(l2)
stopifnot(n1==n2)
x1 <- l1[-n1,1] ; y1 <- l1[-n1,2]
x2 <- l1[-1L,1] ; y2 <- l1[-1L,2]
x3 <- l2[-n2,1] ; y3 <- l2[-n2,2]
x4 <- l2[-1L,1] ; y4 <- l2[-1L,2]
ssi(x1, x2, x3, x4, y1, y2, y3, y4)
}
# do it with all columns of a matrix
ssi_matrix <- function(x, m){
# pairwise combinations
cn <- combn(ncol(m), 2)
test_pair <- function(i){
l1 <- cbind(x, m[,cn[1,i]])
l2 <- cbind(x, m[,cn[2,i]])
pts <- ssi_polyline(l1, l2)
pts[complete.cases(pts),]
}
ints <- lapply(seq_len(ncol(cn)), test_pair)
do.call(rbind, ints)
}
# testing the above
y1 = rnorm(100,0,1)
y2 = rnorm(100,1,1)
m = cbind(y1, y2)
x = 1:100
matplot(x, m, t="l", lty=1)
points(ssi_matrix(x, m))
答案 2 :(得分:1)
延迟响应,但这是使用包SP和RGEOS的“空间”方法。这要求x和y都是数字(或者可以转换为数字)。投影是任意的,但epsg:4269似乎运作良好:
library(sp)
library(rgeos)
# dummy x data
x1 = rnorm(100,0,1)
x2 = rnorm(100,1,1)
#dummy y data
y1 <- seq(1, 100, 1)
y2 <- seq(1, 100, 1)
# convert to a sp object (spatial lines)
l1 <- Line(matrix(c(x1, y1), nc = 2, byrow = F))
l2 <- Line(matrix(c(x2, y2), nc = 2, byrow = F))
ll1 <- Lines(list(l1), ID = "1")
ll2 <- Lines(list(l2), ID = "1")
sl1 <- SpatialLines(list(ll1), proj4string = CRS("+init=epsg:4269"))
sl2 <- SpatialLines(list(ll2), proj4string = CRS("+init=epsg:4269"))
# Calculate locations where spatial lines intersect
int.pts <- gIntersection(sl1, sl2, byid = TRUE)
int.coords <- int.pts@coords
# Plot line data and points of intersection
plot(x1, y1, type = "l")
lines(x2, y2, type = "l", col = "red")
points(int.coords[,1], int.coords[,2], pch = 20, col = "blue")
答案 3 :(得分:1)
我需要另一个应用程序的交集,发现 nograpes 的答案无法正常工作:
# another example
x=seq(-4,6,length.out=10)
x1=dnorm(x, 0, 1)
x2=dnorm(x,2,2)
# Find points where x1 is above x2.
above <- x1 > x2
# Points always intersect when above=TRUE, then FALSE or reverse
intersect.points <- which(diff(above) != 0)
# Find the slopes for each line segment.
x1.slopes <- x1[intersect.points+1] - x1[intersect.points]
x2.slopes <- x2[intersect.points+1] - x2[intersect.points]
# Find the intersection for each segment.
x.points <- x[intersect.points] + ((x2[intersect.points] - x1[intersect.points]) / (x1.slopes-x2.slopes))
y.points <- x1[intersect.points] + (x1.slopes*(x.points-x[intersect.points]))
# Joint points
joint.points <- which(x1 == x2)
x.points <- c(x.points, joint.points)
y.points <- c(y.points, x1[joint.points])
# Plot points
# length(x); length(x1)
plot(x, x1,type='l')
lines(x, x2,type='l',col='red')
points(x.points,y.points,col='blue')
对于这些双正态分布,点是关闭的,在这种情况下尤其是右手边的交点。当 x 轴上的值不是连续整数并且因此连续点的差值不为 1 时,就会发生这种情况。我用 intersect.points
替换了 x[intersect.points]
,这还不够。这是一个遗憾,因为与其他方法相比,该方法相对简单。 baptiste 提供的方法效果更好:
m = cbind(x1, x2)
matplot(x, m, t="l", lty=1)
points(ssi_matrix(x, m))
遵循相同的想法,允许连续 x 值 != 1 的差异的更通用的实现是:
intersect.2lines <- function (x, y1, y2){
above = y1 > y2
intersect.points <- which(diff(above) != 0)
y1.diff <- y1[intersect.points+1] - y1[intersect.points]
y2.diff <- y2[intersect.points+1] - y2[intersect.points]
x.diff <- x[intersect.points+1]-x[intersect.points]
slope1 = y1.diff/x.diff
slope2 = y2.diff/x.diff
intercept1 = y1[intersect.points]-slope1*x[intersect.points]
intercept2 = y2[intersect.points]-slope2*x[intersect.points]
x.points = ifelse(slope1==slope2, NA,
(intercept2-intercept1)/(slope1-slope2))
y.points = ifelse(slope1==slope2, NA,
slope1*x.points+intercept1)
# Joint points
joint.points <- which(y1 == y2)
x.points <- c(x.points, x[joint.points])
y.points <- c(y.points, y1[joint.points])
return(data.frame(x.points=x.points, y.points=y.points))
}
它是维基百科中给出的公式的实现,“给定两条线方程”Line-line intersection
现在的结果与 baptiste 方法产生的结果相同。