SpatialLines 객체의 유사성을 측정하는 방법


9

SpatialLinesR에서 두 개의 객체를 만들었습니다 그림.

이러한 객체는 다음과 같이 생성되었습니다.

library(sp)
xy <- cbind(x,y)
xy.sp = sp::SpatialPoints(xy)
spl1 <- sp::SpatialLines(list(Lines(Line(xy.sp), ID="a")))

이제 어떻게 든 이것이 회전하고 뒤집힌 동일한 선이며 그 차이가 0과 같다는 결론을 내립니다.

이를 위해 maptools패키지 를 사용 하고 라인 # 1을 회전 시킬 수 있습니다 .

spl180 <- maptools::elide(spl1, rotate=180)

그런 다음 rgeos패키지를 사용하여 회전 된 각 라인을 라인 2와 비교하여 확인해야합니다 . 예 :

hdist <- rgeos::gDistance(spl180, spl2, byid=FALSE, hausdorff=TRUE)

그러나 이는 SpatialLines특히 개체 수가 1000 개 정도 인 경우 개체 를 일치시키는 계산 비용이 많이 듭니다 .

이 일을 할 영리한 방법이 있습니까?

PS 또한, 전술 한 접근법은 모든 가능한 회전 및 플립을 보장하지는 않는다.

추신. 라인 # 1이 라인 # 2와 관련하여 축소 된 경우, 라인 # 1과 # 2의 차이는 여전히 0과 같아야합니다.

최신 정보:

여기에 이미지 설명을 입력하십시오

답변:


9

진정으로 범용적인 효과적인 방법은 도형의 표현을 표준화하여 내부 표현의 회전, 평행 이동, 반사 또는 사소한 변경시 변경되지 않도록합니다.

이를위한 한 가지 방법은 연결된 각 모양을 한쪽 끝에서 시작하여 교대로 가장자리 길이와 (서명 된) 각도로 나열하는 것입니다. 길이가 0 인 모서리 나 직각이 없다는 점에서 모양이 "깨끗해야합니다."반사시 변하지 않도록하려면 첫 번째 0이 아닌 값이 음수이면 모든 각도를 무시하십시오.

임의 접속 폴리 때문에 ( N 정점 것이다 N -1 에지에 의해 분리 된 N -2 각도, I는에 편리 발견 R두 배열, 에지 길이 하나 이루어지는 데이터 구조를 사용하여 아래의 코드 $lengths와위한 다른 각도 $angles세그먼트에는 각도가 전혀 없으므로 이러한 데이터 구조에서 길이가 0 인 배열을 처리하는 것이 중요합니다.)

이러한 표현은 사전 식으로 주문할 수 있습니다. 표준화 프로세스 중에 누적 된 부동 소수점 오류에 대해 약간의 여유가 있어야합니다. 우아한 절차는 이러한 좌표를 원래 좌표의 함수로 추정합니다. 아래 솔루션에서 두 가지 길이가 상대적으로 매우 적은 양 으로 다를 때 동일한 길이로 간주되는 더 간단한 방법이 사용 됩니다. 각도는 절대적으로 아주 소량 만 다를 수 있습니다.

기본 방향을 반전하여 변하지 않게하려면 폴리 라인과 반전 사이의 사 전적으로 가장 빠른 표현을 선택하십시오.

여러 부분으로 구성된 폴리 라인을 처리하려면 구성 요소를 사전 식 순서로 정렬하십시오.

유클리드 변환 아래의 등가 클래스를 찾으려면, 다음,

  • 모양의 표준화 된 표현을 만듭니다.

  • 표준화 된 표현을 사전 식으로 정렬합니다.

  • 동일한 순서의 시퀀스를 식별하려면 정렬 된 순서를 통과하십시오.

계산 시간은 O (n * log (n) * N)에 비례합니다. 여기서 n 은 피처 수이고 N 은 피처 에서 가장 많은 정점 수입니다. 이것은 효율적입니다.

폴리 라인 길이, 중심중심 에 대한 모멘트 와 같이 쉽게 계산 된 변하지 않는 기하학적 특성을 기반으로 예비 그룹화를 적용하면 전체 프로세스를 간소화하는 데 종종 적용될 수 있습니다. 그러한 각 예비 그룹 내에서 합동 특징의 하위 그룹 만 찾으면됩니다. 여기에 주어진 완전한 방법은 그렇게 단순한 불변량이 여전히 그들을 구별하지 않을 정도로 매우 유사한 모양에 필요할 것입니다. 예를 들어 래스터 데이터로 구성된 간단한 기능에는 이러한 특성이있을 수 있습니다. 그러나 여기에 제공된 솔루션은 어쨌든 매우 효율적이므로 구현하려는 노력으로 가면 스스로 잘 작동 할 수 있습니다.


왼쪽 그림은 5 개의 폴리 라인과 랜덤 변환, 회전, 반사 및 내부 방향 반전 (표시되지 않음)을 통해 얻은 폴리 라인을 15 개 더 보여줍니다. 오른쪽 그림은 유클리드 동등성 등급에 따라 색상을 지정합니다. 공통 색상의 모든 그림은 일치합니다. 다른 색상은 합리적이지 않습니다.

그림

R코드는 다음과 같습니다. 입력이 500 개의 모양, 500 개의 추가 (동일한) 모양, 모양 당 평균 100 개의 정점으로 업데이트되었을 때이 머신에서 실행 시간은 3 초였습니다.

이 코드는 불완전합니다.R 기본 사전 편곡 정렬이 없기 때문에 처음부터 코딩하는 느낌이 들지 않기 때문에 표준화 된 각 모양의 첫 번째 좌표에서 정렬을 수행하기 만하면됩니다. 여기에서 생성 된 임의의 모양에는 문제가 없지만 프로덕션 작업에는 전체 사전 사전 정렬이 구현되어야합니다. order.shape이 변경에 의해 영향을받는 것은 기능 뿐입니다. 입력은 표준화 된 모양의 목록이며 s출력은 s정렬 할 인덱스 순서입니다 .

#
# Create random shapes.
#
n.shapes <- 5      # Unique shapes, up to congruence
n.shapes.new <- 15 # Additional congruent shapes to generate
p.mean <- 5        # Expected number of vertices per shape
set.seed(17)       # Create a reproducible starting point
shape.random <- function(n) matrix(rnorm(2*n), nrow=2, ncol=n)
shapes <- lapply(2+rpois(n.shapes, p.mean-2), shape.random)
#
# Randomly move them around.
#
move.random <- function(xy) {
  a <- runif(1, 0, 2*pi)
  reflection <- sign(runif(1, -1, 1))
  translation <- runif(2, -8, 8)
  m <- matrix(c(cos(a), sin(a), -sin(a), cos(a)), 2, 2) %*%
    matrix(c(reflection, 0, 0, 1), 2, 2)
  m <- m %*% xy + translation
  if (runif(1, -1, 0) < 0) m <- m[ ,dim(m)[2]:1]
  return (m)
}
i <- sample(length(shapes), n.shapes.new, replace=TRUE)
shapes <- c(shapes, lapply(i, function(j) move.random(shapes[[j]])))
#
# Plot the shapes.
#
range.shapes <- c(min(sapply(shapes, min)), max(sapply(shapes, max)))
palette(gray.colors(length(shapes)))
par(mfrow=c(1,2))
plot(range.shapes, range.shapes, type="n",asp=1, bty="n", xlab="", ylab="")
invisible(lapply(1:length(shapes), function(i) lines(t(shapes[[i]]), col=i, lwd=2)))
#
# Standardize the shape description.
#
standardize <- function(xy) {
  n <- dim(xy)[2]
  vectors <- xy[ ,-1, drop=FALSE] - xy[ ,-n, drop=FALSE]
  lengths <- sqrt(colSums(vectors^2))
  if (which.min(lengths - rev(lengths))*2 < n) {
    lengths <- rev(lengths)
    vectors <- vectors[, (n-1):1]
  }
  if (n > 2) {
    vectors <- vectors / rbind(lengths, lengths)
    perps <- rbind(-vectors[2, ], vectors[1, ])
    angles <- sapply(1:(n-2), function(i) {
      cosine <- sum(vectors[, i+1] * vectors[, i])
      sine <- sum(perps[, i+1] * vectors[, i])
      atan2(sine, cosine)
    })
    i <- min(which(angles != 0))
    angles <- sign(angles[i]) * angles
  } else angles <- numeric(0)
  list(lengths=lengths, angles=angles)
}
shapes.std <- lapply(shapes, standardize)
#
# Sort lexicographically.  (Not implemented: see the text.)
#
order.shape <- function(s) {
  order(sapply(s, function(s) s$lengths[1]))
}
i <- order.shape(shapes.std)
#
# Group.
#
equal.shape <- function(s.0, s.1) {
  same.length <- function(a,b) abs(a-b) <= (a+b) * 1e-8
  same.angle <- function(a,b) min(abs(a-b), abs(a-b)-2*pi) < 1e-11
  r <- function(u) {
    a <- u$angles
    if (length(a) > 0) {
      a <- rev(u$angles)
      i <- min(which(a != 0))
      a <- sign(a[i]) * a
    }
    list(lengths=rev(u$lengths), angles=a)
  }
  e <- function(u, v) {
    if (length(u$lengths) != length(v$lengths)) return (FALSE)
    all(mapply(same.length, u$lengths, v$lengths)) &&
      all(mapply(same.angle, u$angles, v$angles))
    }
  e(s.0, s.1) || e(r(s.0), s.1)
}
g <- rep(1, length(shapes.std))
for (j in 2:length(i)) {
  i.0 <- i[j-1]
  i.1 <- i[j]
  if (equal.shape(shapes.std[[i.0]], shapes.std[[i.1]])) 
    g[j] <- g[j-1] else g[j] <- g[j-1]+1
}
palette(rainbow(max(g)))
plot(range.shapes, range.shapes, type="n",asp=1, bty="n", xlab="", ylab="")
invisible(lapply(1:length(i), function(j) lines(t(shapes[[i[j]]]), col=g[j], lwd=2)))

변환 그룹에 임의의 확장 (또는 "등가성")이 포함 된 경우 등가 클래스는 아핀 지오메트리 의 일치 클래스입니다 . 이 복잡한 문제는 쉽게 처리 할 수 ​​있습니다. 예를 들어 모든 폴리 라인을 총 단위 길이로 표준화합니다.
whuber

매우 감사합니다. 단 하나의 질문 : 모양을 SpatialLine 또는 SpatialPolygon으로 표시해야합니까?
Klausos Klausos 2018 년

다각형은 또 다른 합병증을 만듭니다. 경계에는 명확한 끝 점이 없습니다. 이를 처리하는 방법에는 여러 가지가 있습니다. 예를 들어 xy 사전 순으로 먼저 정렬하는 정점에서 시작하여 다각형 주위에서 시계 반대 방향으로 진행하는 정점을 표준화하는 등의 방법이 있습니다. (토폴로지로 "깨끗한"연결된 다각형에는 하나의 꼭짓점이 있습니다.) 모양이 다각형 또는 폴리 라인으로 간주되는지 여부는 어떤 종류의 특징을 나타내는 지에 따라 달라집니다. 닫힌 점 목록에 대한 본질적인 방법은 없습니다 폴리 라인 또는 폴리곤으로 의도되었습니다.
whuber

간단한 질문에 대해 죄송하지만 귀하의 모범을 이해하도록 요청해야합니다. 객체 shapes.std에는 $ lengths와 $ angles가 모두 있습니다. 그러나 xy 데이터에서이 코드를 실행하면 (예 : [1,] 3093.5 -2987.8 [2,] 3072.7 -2991.0 등) 각도를 추정하지 않고 도형을 그리지 않습니다. plot (shapes [[1]])을 실행하면 폴리 라인을 명확하게 볼 수 있습니다. 그렇다면 데이터에서 코드를 테스트 할 수 있도록 R에 폴리 라인을 어떻게 저장해야합니까?
Klausos Klausos 2018 년

(x, y) 좌표 배열과 같은 데이터 구조로 시작했습니다. 내 배열은 그 좌표를 열에 넣습니다 (마치 rbind(x,y)대신 사용했던 것처럼 cbind(x,y)). 이것이 필요한 전부입니다 : sp라이브러리가 사용되지 않습니다. 당신이 구체적으로 이루어집니다 팔로우하고 싶은 경우에, 나는 당신이 말하는, 함께 시작하는 것이 좋습니다 n.shapes <- 2, n.shapes.new <- 3하고 p.mean <- 1. 그런 다음 shapes, shapes.std등은 모두 쉽게 검사 할 수있을 정도로 작습니다. 이 모든 것을 처리하는 우아하고 "올바른"방법 은 표준화 된 피처 표현 클래스 를 만드는 것 입니다.
whuber

1

당신은 임의의 회전과 팽창으로 많은 것을 요구하고 있습니다! Hausdorff 거리가 얼마나 유용한 지 잘 모르지만 확인하십시오. 저의 접근 방식은 저렴한 데이터를 통해 확인할 사례 수를 줄이는 것입니다. 예를 들어, 두 줄 문자열의 길이가 정수 비율이 아닌 경우 ( 정수 / 졸업 스케일링 가정) 값 비싼 비교를 건너 뛸 수 있습니다. 바운딩 박스 영역 또는 볼록 껍질 영역의 비율이 좋은지 마찬가지로 확인할 수 있습니다. 시작 / 종료까지의 거리 또는 각도와 같이 중심에 대해 싸구려 점검이 많이 있다고 확신합니다.

그런 다음에 만 스케일링을 감지하면 실행을 취소하고 비용이 많이 드는 점검을 수행하십시오.

설명 : 사용중인 패키지를 모르겠습니다. 정수 비율로 나는 두 거리를 나누고 결과가 정수인지 확인하고 그렇지 않은 경우 해당 값을 반전시키고 (잘못된 순서를 선택했을 수 있음) 다시 확인해야합니다. 정수를 얻거나 충분히 가까워지면 스케일링이 진행되고 있다고 추정 할 수 있습니다. 아니면 두 가지 다른 모양 일 수도 있습니다.

경계 상자의 경우 사각형을 나타내는 사각형의 반대 지점이있을 수 있으므로 영역을 가져 오는 것은 간단한 산술입니다. 비율 비교의 기본 원리는 결과가 제곱된다는 것만 같습니다. R 패키지에서 멋지게 얻을 수 없다면 볼록 껍질을 신경 쓰지 마십시오. 어쨌든 충분히 저렴하지는 않을 것입니다.


고마워 두 줄의 길이가 정수 비율이 아닌지 감지하는 방법을 설명해 주시겠습니까? 또한 "경계 박스 영역 또는 볼록 껍질 선체 영역의 비율이
좋은지

예를 들어 공간 데이터에서 공간 경계 상자를 추출하면 spl <-sp :: SpatialLines (list (Lines (Line (xy.sp), ID = i))) b <-bbox ( spl)
Klausos Klausos

메인 포스트를 확장했습니다.
lynxlynxlynx 2018 년

"정수를 얻거나 충분히 가까워지면 스케일링이 진행중인 것으로 추정 할 수 있습니다." 사용자가 1.4 정도의 스케일을 적용 할 수 없습니까?
Germán Carrillo

물론, 특히 나중에 편집 할 때 내 가정이 명확 해졌습니다. 나는 웹 맵 스타일 확대 / 축소를 상상하고있었습니다.
lynxlynxlynx

1

이러한 폴리 라인을 비교하는 좋은 방법은 각 정점에서 시퀀스 (거리, 회전 각도) P1, P2, ..., PN시퀀스로 표현하는 것 입니다. points로 구성된 라인의 경우 이러한 시퀀스는 다음과 같습니다.

(거리 (P1P2), 각도 (P1, P2, P3), 거리 (P2P3), ..., 각도 (P (N-2), P (N-1), PN), 거리 (P (N-1 PN)).

귀하의 요구 사항에 따라 두 시퀀스는 해당 시퀀스가 ​​동일한 경우에만 동일합니다 (차수 및 각도 방향의 모듈로). 숫자 순서를 비교하는 것은 쉽지 않습니다.

각 폴리 라인 시퀀스를 한 번만 계산하고 lynxlynxlynx가 제안한 것처럼 동일한 사소한 특성 (길이, 정점 수 ...)을 갖는 폴리 라인에 대해서만 시퀀스 유사성을 테스트하면 계산이 정말 빨라야합니다!


이것이 올바른 생각입니다. 그러나 실제로 작동하려면 반사, 내부 방향, 다중 연결된 구성 요소의 가능성 및 부동 소수점 반올림 오류와 같은 많은 세부 사항을 해결해야합니다. 그들은 내가 제공 한 솔루션에서 논의됩니다.
whuber

그렇습니다, 나는 단지 주요 아이디어를 설명했습니다. 귀하의 답변이 훨씬 더 완전합니다 (자주 :-)
julien
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.