Mam SpatialPointsDataFrame
trochę dodatkowych danych. Chciałbym wydobyć te punkty wewnątrz wielokąta i jednocześnie zachowaćSPDF
obiekt i odpowiadające mu dane.
Do tej pory nie miałem szczęścia i korzystałem z dopasowywania i łączenia za pomocą wspólnego identyfikatora, ale działa to tylko dlatego, że mam dane w siatce z indywidualnymi identyfikatorami.
Oto szybki przykład: szukam punktów wewnątrz czerwonego kwadratu.
library(sp)
set.seed(357)
pts <- data.frame(x = rnorm(100), y = rnorm(100), var1 = runif(100), var2 = sample(letters, 100, replace = TRUE))
coordinates(pts) <- ~ x + y
class(pts)
plot(pts)
axis(1); axis(2)
ply <- matrix(c(-1,-1, 1,-1, 1,1, -1,1, -1,-1), ncol = 2, byrow = TRUE)
ply <- SpatialPolygons(list(Polygons(list(Polygon(ply)), ID = 1)))
ply <- SpatialPolygonsDataFrame(Sr = ply, data = data.frame(polyvar = 357))
plot(ply, add = TRUE, border = "red")
Najbardziej oczywistym podejściem byłoby użycie over
, ale zwraca dane z wielokąta.
> over(pts, ply)
polyvar
1 NA
2 357
3 357
4 NA
5 357
6 357
Odpowiedzi:
Z
sp::over
pomocy:Więc jeśli przekonwertujesz
SpatialPolygonsDataFrame
naSpatialPolygons
, otrzymasz wektor indeksów i możesz podzielić swoje punkty naNA
:Dla wątpiących, oto dowód, że narzut związany z konwersją nie stanowi problemu:
Dwie funkcje - najpierw metoda Jeffreya Evansa, potem moja oryginalna, potem moja zhakowana konwersja, a następnie wersja oparta na
gIntersects
odpowiedzi Josha O'Briena:Teraz na przykład w świecie rzeczywistym rozrzuciłem kilka losowych punktów nad
columbus
zestawem danych:Wygląda dobrze
Sprawdź, czy funkcje robią to samo:
I uruchom 500 razy na potrzeby testów porównawczych:
Według mojej intuicji, nie jest to wielki narzut, w rzeczywistości może być mniejszy narzut niż konwertowanie wszystkich indeksów wierszy na znak iz powrotem lub uruchamianie na.omit, aby uzyskać brakujące wartości. Co nawiasem mówiąc, prowadzi do innego trybu awarii
evans
funkcji ...Jeśli wiersz ramki danych wielokątów jest wszystkim
NA
(co jest całkowicie poprawne), wówczas nakładka zSpatialPolygonsDataFrame
punktami w tym wielokącie wytworzy wyjściową ramkę danych ze wszystkimiNA
s, któreevans()
następnie spadną:ALE
gIntersects
jest szybszy, nawet z koniecznością zamiatania macierzy, aby sprawdzić przecięcia w R zamiast w kodzie C. Podejrzewam, że maprepared geometry
umiejętności GEOS, tworząc indeksy przestrzenne - tak, przyprepared=FALSE
czym zajmuje to nieco więcej, około 5,5 sekundy.Dziwię się, że nie ma funkcji ani prostego zwracania wskaźników, ani punktów. Kiedy pisałem
splancs
20 lat temu, funkcje punkt-w-wielokącie miały zarówno ...źródło
sp
zapewnia krótszy formularz do wybierania obiektów w oparciu o przecięcie przestrzenne, zgodnie z przykładem PO:od:
Za kulisami jest to skrót
Należy zauważyć, że istnieje
geometry
metoda, która upuszcza atrybuty:over
zmienia zachowanie, jeśli drugi argument ma atrybuty, czy nie (to było zamieszanie OP). Działa to we wszystkich klasach Spatial *sp
, chociaż niektóreover
metody tego wymagająrgeos
, zobacz tę winietę, aby uzyskać szczegółowe informacje, np. Przypadek wielokrotnego dopasowania nakładających się wielokątów.źródło
Z tobą byłeś na dobrej drodze. Nazwy zwracanego obiektu odpowiadają indeksowi rzędów punktów. Możesz wdrożyć swoje dokładne podejście za pomocą zaledwie kilku dodatkowych wierszy kodu.
źródło
Czy o to ci chodzi?
Jedna uwaga na temat edycji:
apply()
konieczne jest wywołanie zawijania do dowolnychSpatialPolygons
obiektów, które mogą zawierać więcej niż jeden element wielokąta. Dzięki @Spacedman za nakłonienie mnie do zademonstrowania, jak zastosować to w bardziej ogólnym przypadku.źródło
ply
działa okropnie, jeśli ma więcej niż jedną funkcję, ponieważgIntersects
zwraca macierz z jednym wierszem dla każdej cechy. Prawdopodobnie możesz zamienić wiersze na wartość PRAWDA.apply(gIntersects(pts, ply, byid=TRUE), 2, any)
. Właściwie przejdę do odpowiedzi i przestawię odpowiedź na to, ponieważ obejmuje to również przypadek pojedynczego wielokąta.any
. To może być nieznacznie szybsze niż wersja, którą właśnie przetestowałem.obrien
irowlings2
biegnie szyja z szyją,obrien
może z 2% szybszym.pp
powinno mieć znakID
wskazujący, w którym wielokącie znajdują się punkty.Oto możliwe podejście przy użyciu
rgeos
pakietu. Zasadniczo korzysta zgIntersection
funkcji, która umożliwia przecięcie dwóchsp
obiektów. Wyodrębniając identyfikatory punktów znajdujących się w obrębie wielokąta, możesz następnie podzielić swój oryginałSpatialPointsDataFrame
, zachowując wszystkie odpowiednie dane. Kod jest prawie samoobjaśniający, ale jeśli są jakieś pytania, możesz je zadać!źródło
tmp
byćpts.intersect
? Także parsowanie zwróconych nazw jest zależne od nieudokumentowanego zachowania.tmp
, zapomniałeś go usunąć po zakończeniu kodu. Masz rację także podczas analizowaniadimnames
. To było szybkie rozwiązanie, które zapewniło pytającemu szybką odpowiedź, a na pewno są lepsze (i bardziej uniwersalne) podejścia, na przykład twoje :-)Istnieje niezwykle proste rozwiązanie z wykorzystaniem
spatialEco
biblioteki.Sprawdź wynik:
źródło