SpatialLines nesnelerinin benzerliği nasıl ölçülür


9

SpatialLinesR'de iki nesne yarattım şekil.

Bu nesneler şu şekilde yaratıldı:

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

Şimdi bir şekilde bunun aynı çizgi döndürülmüş ve çevrilmiş olduğu ve aralarındaki farkın 0'a eşit olduğu (yani şekil eşit olduğu) sonucuna varmak istiyorum.

Bunu yapmak için, maptoolspaket kullanabilir ve 1 numaralı satırı döndürebilir, örneğin:

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

Döndürülen her çizgi daha sonra rgeospaket kullanılarak # 2'ye karşı kontrol edilmelidir , örn .:

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

Bununla birlikte, SpatialLinesözellikle nesne sayısı 1000 civarındaysa, nesneleri eşleştirmek için hesaplama açısından pahalı bir yoldur .

Bu işi yapmanın akıllıca bir yolu var mı?

PS Dahası, yukarıda tarif edilen yaklaşım olası tüm rotasyonları ve döndürmeleri garanti etmez.

NOT2. # 1 satırı, # 2 satırına göre uzaklaştırılırsa, # 1 ve # 2 arasındaki fark yine de 0'a eşit olmalıdır.

GÜNCELLEME:

resim açıklamasını buraya girin

Yanıtlar:


9

Herhangi bir gerçekten genel amaçlı etkili yöntem, şekillerin temsilini standart hale getirecek, böylece iç gösterimdeki dönme, çeviri, yansıma veya önemsiz değişiklikler üzerine değişmeyeceklerdir.

Bunu yapmanın bir yolu, bağlı her şekli bir uçtan başlayarak alternatif bir kenar uzunlukları ve (işaretli) açı dizisi olarak listelemektir. (Şeklin sıfır uzunluklu kenarları veya düz açıları olmaması anlamında "temiz" olması gerekir.) Bu değişmezi yansıma altında yapmak için, ilk sıfır olmayan negatif ise tüm açıları ortadan kaldırın.

( N köşelerin herhangi bir bağlı çoklu çizgisi n- 2 açı ile ayrılmış n- 1 kenara sahip olacağından, aşağıdaki kodda biri kenar uzunlukları için diğeri kenar uzunlukları için olmak üzere iki diziden oluşan bir veri yapısının kullanılmasını uygun buldum . açıları, bu tür bir veri yapısı içinde sıfır uzunluklu dizi işlemek için önemlidir, böylece. bir doğru parçası, hiçbir açıları olacaktır.)R$lengths$angles

Bu tür temsiller sözlükbilimsel olarak sipariş edilebilir. Standardizasyon işlemi sırasında biriken kayan nokta hataları için bir miktar izin verilmelidir. Zarif bir prosedür bu hataları orijinal koordinatların bir fonksiyonu olarak tahmin edecektir. Aşağıdaki çözümde, göreli olarak çok küçük bir miktarda farklılık gösterdiklerinde iki uzunluğun eşit olduğu düşünülen daha basit bir yöntem kullanılmaktadır . Açılar mutlak olarak sadece çok az miktarda farklılık gösterebilir.

Onları altta yatan yönelimin tersine çevrilmesi altında değişmez kılmak için, çoklu çizginin ters çevrimi ile sözlükbilimsel olarak en erken temsili seçin.

Çok parçalı polietilenleri işlemek için bileşenlerini sözlükbilimsel düzende düzenleyin.

Öklid dönüşümleri altındaki denklik sınıflarını bulmak için ,

  • Şekillerin standartlaştırılmış temsillerini oluşturun.

  • Standartlaştırılmış gösterimlerin sözlükbilimsel bir türünü gerçekleştirin.

  • Eşit temsillerin dizilerini tanımlamak için sıralı sıradan bir geçiş yapın.

Hesaplama süresi O (n * log (n) * N) ile orantılıdır; burada n , özellik sayısıdır ve N , herhangi bir özellikteki en fazla köşe noktasıdır. Bu etkilidir.

Muhtemelen, çok hatlı uzunluk, merkez ve o merkezle ilgili anlar gibi kolayca hesaplanan değişmez geometrik özelliklere dayanan bir ön gruplamanın tüm süreci kolaylaştırmak için uygulanabileceğini belirtmek gerekir. Kişinin sadece bu tür her bir ön grupta uyumlu özelliklerin alt gruplarını bulması gerekir. Burada verilen tam yönteme, aksi takdirde bu kadar basit benzerlerin hala onları ayırt etmeyecek kadar benzer olacak şekiller için gerekli olacaktır. Raster verilerinden oluşturulan basit özellikler, örneğin bu özelliklere sahip olabilir. Bununla birlikte, burada verilen çözüm zaten çok verimli olduğu için, eğer onu uygulama çabalarına gidecek olursa, kendi başına iyi çalışabilir.


Misal

Soldaki şekil, rasgele çeviri, döndürme, yansıma ve iç yönelimin (görünür olmayan) tersine çevrilmesi ile elde edilen beş çoklu çizgiyi artı 15 tane daha göstermektedir. Sağ figür onları Öklid eşdeğerlik sınıflarına göre renklendirir: ortak bir rengin tüm figürleri uyumludur; farklı renkler uyumlu değildir.

şekil

Rkodu takip eder. Girişler 500 şekle, 500 ekstra (uyumlu) şekle, şekil başına ortalama 100 köşeye güncellendiğinde, bu makinedeki yürütme süresi 3 saniyeydi.

Bu kod eksik: çünkü Ryerel bir sözlükbilimsel sıralama yok ve sıfırdan bir kodlama gibi hissetmedim, ben sadece her standart şeklin ilk koordinatında sıralama gerçekleştirin. Bu, burada oluşturulan rastgele şekiller için iyi olacaktır, ancak üretim çalışmaları için tam bir sözlükbilimsel sıralama uygulanmalıdır. İşlev order.shape, bu değişiklikten etkilenen tek işlev olacaktır. Girdisi standartlaştırılmış şeklin bir listesidir sve çıktısı sonu sıralayacak dizin dizisidir .

#
# 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)))

Biri, dönüşüm grubuna keyfi dilatasyonlar (veya "izotetler") içerdiğinde, denklik sınıfları afin geometrinin uyum sınıflarıdır . Bu komplikasyon kolayca giderilebilir: örneğin, tüm birim çizgilerini toplam birim uzunluğa sahip olacak şekilde standartlaştırın.
whuber

Çok teşekkürler. Sadece bir soru: Şekiller SpatialLines veya SpatialPolygons olarak temsil edilmeli mi?
Klausos Klausos

Çokgenler başka bir komplikasyon yaratır: sınırlarının kesin bir uç noktası yoktur. Bunu idare etmenin birçok yolu vardır, örneğin, ilk olarak xy sözlükbilimsel sırayla sıralanan tepe noktasında başlamak ve çokgen etrafında saat yönünün tersine ilerlemek gibi gösterimi standartlaştırmak gibi. (Topolojik olarak "temiz" bağlı bir çokgenin böyle bir tepe noktası yalnızca bir tane olacaktır.) Bir şeklin çokgen veya çokgen olarak kabul edilip edilmediği, ne tür bir özelliği temsil ettiğine bağlıdır: bir çoklu çizgi ya da çokgen olması amaçlanmıştır.
whuber

Basit bir soru için özür dilerim, ancak örneğinizi anlamasını istemeliyim. Nesnenin şekiller.std dosyasının hem $ uzunlukları hem de $ açıları vardır. Ancak, bu kodu xy verilerimde çalıştırırsam (örneğin [1,] 3093.5 -2987.8 [2, 3072.7 -2991.0 vb.), Açıları tahmin etmez, şekil çizmez. Eğer arsa (şekiller [[1]]) çalıştırırsam, o zaman çoklu çizgimi net bir şekilde görebilirim. Öyleyse, kodumu verilerimde test edebilmek için R'de polylines'i nasıl kaydetmeliyim?
Klausos Klausos

Yaptığınız veri yapısıyla başladım: (x, y) koordinatlarından oluşan bir dizi. Dizilerim bu koordinatları sütunlara koydu (sanki kullandığınız rbind(x,y)gibi cbind(x,y)). Tüm ihtiyacınız olan bu: spkütüphane kullanılmıyor. Eğer detaylı olarak yapılanlara takip etmek istiyorsanız, sana diyelim ki, işe başlamak önermek n.shapes <- 2, n.shapes.new <- 3ve p.mean <- 1. Sonra shapes, shapes.stdvb. Kolayca incelenebilecek kadar küçüktür. Tüm bunlarla başa çıkmanın zarif ve "doğru" yolu , standartlaştırılmış bir özellik temsili sınıfı oluşturmak olacaktır .
whuber

1

Keyfi rotasyon ve genişleme ile çok şey istiyorsun! Ne kadar yararlı Hausdorff mesafe orada olurdu emin değilim, ama göz atın. Benim yaklaşımım ucuz verilerle kontrol edilecek vaka sayısını azaltmak olacaktır. Örneğin, iki çizginin uzunluğu bir tamsayı oranı değilse ( tamsayı / dereceli ölçekleme varsayarak ) pahalı karşılaştırmaları atlayabilirsiniz . Benzer şekilde sınırlayıcı kutu alanının veya dışbükey gövde alanlarının güzel bir oranda olup olmadığını kontrol edebilirsiniz. Eminim, başlangıç ​​/ bitişten mesafeler veya açılar gibi sentroide karşı yapabileceğiniz birçok ucuz kontrol vardır.

Ancak o zaman, ölçeklendirme tespit ederseniz, geri alın ve gerçekten pahalı kontroller yapın.

Açıklama: Kullandığınız paketleri bilmiyorum. Tamsayı oranına göre, her iki mesafeyi de bölmelisiniz, sonucun bir tamsayı olup olmadığını kontrol edin, eğer değilse, bu değeri ters çevirin (yanlış sırayı seçmiş olabilirsiniz) ve tekrar kontrol edin. Bir tamsayı alırsanız veya yeterince yakın olursanız, ölçeklemenin devam ettiğini görebilirsiniz. Ya da sadece iki farklı şekil olabilir.

Sınırlayıcı kutuya gelince, muhtemelen onu temsil eden dikdörtgenin zıt noktalarına sahipsiniz, bu nedenle alanı çıkarmak basit aritmetiktir. Oran karşılaştırmasının arkasındaki prensip aynıdır, sadece sonucun karesi alınır. Eğer bu R paketinden güzelce alamazsanız dışbükey gövdelerle uğraşmayın, sadece bir fikirdi (muhtemelen yeterince ucuz değil).


Çok teşekkürler. İki çizginin uzunluğunun bir tamsayı oranı olup olmadığını nasıl tespit edeceğinizi açıklar mısınız? Ayrıca, "sınırlayıcı kutu alanı veya dışbükey gövde alanları güzel bir
orandaysa

Örneğin, uzamsal verilerden uzamsal sınırlama kutusunu ayıklarsam, iki nokta alırım: spl <- sp :: SpatialLines (list (Lines (Line (xy.sp), ID = i))) b <- bbox ( spl)
Klausos Klausos

Ana gönderi uzatıldı.
lynxlynxlynx

"Eğer bir tamsayı veya yeterince yakın alırsanız, belki de ölçekleme devam ediyor olabilir." Bir kullanıcı 1,4 veya daha fazla bir ölçek uygulayamadı mı?
Germán Carrillo

Tabii, ama benim varsayım özellikle daha sonraki düzenlemelerle netleştirildi. Biri güzel sınırlı webmap tarzı yakınlaştırma, hayal ediyordum.
lynxlynxlynx

1

Bu çoklu çizgileri karşılaştırmak için iyi bir yöntem, her köşede bir dizi (mesafeler, dönüş açıları) olarak bir temsile dayanmak olacaktır: Noktalardan oluşan bir çizgi için P1, P2, ..., PN, bu dizi şu şekilde olacaktır:

(mesafe (P1P2), açı (P1, P2, P3), mesafe (P2P3), ..., açı (P (N-2), P (N-1), PN), mesafe (P (N-1) ) PN)).

Gereksinimlerinize göre, iki satır, yalnızca ve karşılık gelen dizileri aynı ise (düzen ve açı yönünü modulo) eşittir. Sayı dizilerinin karşılaştırılması önemsizdir.

Her çoklu hat dizisini yalnızca bir kez hesaplayarak ve lynxlynxlynx tarafından önerildiği gibi, sıra benzerliğini sadece aynı önemsiz özelliklere (uzunluk, köşe sayısı ...) sahip olan çoklu çizgi için test ederek, hesaplama gerçekten hızlı olmalıdır!


Bu doğru fikir. Aslında çalışması için yansımalarla başa çıkma, iç yönelim, çoklu bağlı bileşenlerin olasılığı ve kayan nokta yuvarlama hatası gibi birçok ayrıntıya değinmek gerekir. Sağladığım çözümde tartışılıyorlar.
whuber

Evet, sadece ana fikri anlattım. Cevabınız oldukça daha eksiksiz (sık sık :-) gibi
julien
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.