SpatialPointsDataFrame और SPDF डेटा को संरक्षित करने पर बहुभुज कैसे उपरिशायी है?


17

मेरे पास SpatialPointsDataFrameकुछ अतिरिक्त डेटा हैं। मैं एक बहुभुज के अंदर और एक ही समय में उन बिंदुओं को निकालना चाहता हूं, जो SPDFऑब्जेक्ट और उसके संबंधित डेटा को संरक्षित करते हैं।

अब तक मेरी किस्मत बहुत कम थी और एक आम आईडी के माध्यम से मिलान और विलय का सहारा लिया था, लेकिन यह केवल काम करता है क्योंकि मैंने व्यक्तिगत आईडी के साथ डेटा को ग्रिड किया है।

यहां एक त्वरित उदाहरण है, मैं लाल वर्ग के अंदर के बिंदुओं की तलाश कर रहा हूं।

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

सबसे स्पष्ट दृष्टिकोण का उपयोग करना होगा over, लेकिन यह बहुभुज से डेटा लौटाता है।

> over(pts, ply)
    polyvar
1        NA
2       357
3       357
4        NA
5       357
6       357

1
एक प्रतिलिपि प्रस्तुत करने योग्य उदाहरण प्रदान करने के लिए धन्यवाद। किसी समस्या को समझने की कोशिश में हमेशा मदद करता है!
fdetsch

जवाबों:


21

से sp::overमदद:

 x = "SpatialPoints", y = "SpatialPolygons" returns a numeric
      vector of length equal to the number of points; the number is
      the index (number) of the polygon of ‘y’ in which a point
      falls; NA denotes the point does not fall in a polygon; if a
      point falls in multiple polygons, the last polygon is
      recorded.

इसलिए यदि आप अपने को परिवर्तित SpatialPolygonsDataFrameकरने के लिए SpatialPolygonsतुम वापस अनुक्रमणिका का एक वेक्टर मिलता है और आप पर अपने अंक सबसेट कर सकते हैं NA:

> over(pts,as(ply,"SpatialPolygons"))
  [1] NA  1  1 NA  1  1 NA NA  1  1  1 NA NA  1  1  1  1  1 NA NA NA  1 NA  1 NA
 [26]  1  1  1 NA NA NA NA NA  1  1 NA NA NA  1  1  1 NA  1  1  1 NA NA NA  1  1
 [51]  1 NA NA NA  1 NA  1 NA  1 NA NA  1 NA  1  1 NA  1  1 NA  1 NA  1  1  1  1
 [76]  1  1  1  1  1 NA NA NA  1 NA  1 NA NA NA NA  1  1 NA  1 NA NA  1  1  1 NA

> nrow(pts)
[1] 100
> pts = pts[!is.na(over(pts,as(ply,"SpatialPolygons"))),]
> nrow(pts)
[1] 54
> head(pts@data)
         var1 var2
2  0.04001092    v
3  0.58108350    v
5  0.85682609    q
6  0.13683264    y
9  0.13968804    m
10 0.97144627    o
> 

संदेहियों के लिए, यहाँ सबूत है कि रूपांतरण ओवरहेड एक समस्या नहीं है:

दो कार्य - पहले जेफरी इवांस विधि, फिर मेरा मूल, फिर मेरा हैक किया गया रूपांतरण, फिर gIntersectsजोश ओ'ब्रायन के उत्तर पर आधारित एक संस्करण :

evans <- function(pts,ply){
  prid <- over(pts,ply)
  ptid <- na.omit(prid) 
  pt.poly <- pts[as.numeric(as.character(row.names(ptid))),]
  return(pt.poly)
}

rowlings <- function(pts,ply){
  return(pts[!is.na(over(pts,as(ply,"SpatialPolygons"))),])
}

rowlings2 <- function(pts,ply){
  class(ply) <- "SpatialPolygons"
  return(pts[!is.na(over(pts,ply)),])
}

obrien <- function(pts,ply){
pts[apply(gIntersects(columbus,pts,byid=TRUE),1,sum)==1,]
}

अब एक वास्तविक दुनिया के उदाहरण के लिए, मैंने columbusडेटा सेट पर कुछ यादृच्छिक बिंदुओं को बिखेर दिया है :

require(spdep)
example(columbus)
pts=data.frame(
    x=runif(100,5,12),
    y=runif(100,10,15),
    z=sample(letters,100,TRUE))
coordinates(pts)=~x+y

अछा लगता है

plot(columbus)
points(pts)

कार्यों की जाँच करें एक ही काम कर रहे हैं:

> identical(evans(pts,columbus),rowlings(pts,columbus))
[1] TRUE

और बेंचमार्किंग के लिए 500 बार चलाएं:

> system.time({for(i in 1:500){evans(pts,columbus)}})
   user  system elapsed 
  7.661   0.600   8.474 
> system.time({for(i in 1:500){rowlings(pts,columbus)}})
   user  system elapsed 
  6.528   0.284   6.933 
> system.time({for(i in 1:500){rowlings2(pts,columbus)}})
   user  system elapsed 
  5.952   0.600   7.222 
> system.time({for(i in 1:500){obrien(pts,columbus)}})
  user  system elapsed 
  4.752   0.004   4.781 

मेरे अंतर्ज्ञान के अनुसार, यह एक महान उपरि नहीं है, वास्तव में यह चरित्र और पीठ के लिए सभी पंक्ति अनुक्रमों को परिवर्तित करने या लापता मूल्यों को प्राप्त करने के लिए na.omit चलाने की तुलना में एक उपरि से कम हो सकता है। जो संयोग से एक और विफलता मोड की ओर जाता हैevans समारोह ...

यदि बहुभुज डेटा फ़्रेम की एक पंक्ति सभी NA(जो पूरी तरह से वैध है), तो SpatialPolygonsDataFrameउस बहुभुज में बिंदुओं के साथ ओवरले सभी NAएस के साथ एक आउटपुट डेटा फ़्रेम का उत्पादन evans()करेगा , जो तब ड्रॉप हो जाएगा:

> columbus@data[1,]=rep(NA,20)
> columbus@data[5,]=rep(NA,20)
> columbus@data[17,]=rep(NA,20)
> columbus@data[15,]=rep(NA,20)
> set.seed(123)
> pts=data.frame(x=runif(100,5,12),y=runif(100,10,15),z=sample(letters,100,TRUE))
> coordinates(pts)=~x+y
> identical(evans(pts,columbus),rowlings(pts,columbus))
[1] FALSE
> dim(evans(pts,columbus))
[1] 27  1
> dim(rowlings(pts,columbus))
[1] 28  1
> 

B gIntersects, C कोड के बजाय R में चौराहों की जांच करने के लिए मैट्रिक्स को स्वीप करने के साथ भी तेज़ है। मुझे इसके prepared geometryGEOS के कौशल पर संदेह है , स्थानिक सूचकांक बनाते हैं - हाँ, इसके साथ prepared=FALSEथोड़ा लंबा समय लगता है, लगभग 5.5 सेकंड।

मुझे आश्चर्य है कि सूचकांकों या बिंदुओं को सीधे वापस करने का कोई कार्य नहीं है। जब मैंने लिखा था splancs20 साल पहले बिंदु-बहुभुज कार्यों दोनों में था ...


महान, यह कई बहुभुजों के लिए भी काम करता है (मैंने जोशुआ के जवाब में खेलने के लिए एक उदाहरण जोड़ा है)।
रोमन लुसट्रिक

SpatialPolygons ऑब्जेक्ट में बड़े बहुभुज डेटासेट बल के साथ ओवरहेड का एक बहुत कुछ है और आवश्यक नहीं है। SpatialPolygonsDataFrame पर "ओवर" लगाने से पंक्ति इंडेक्स वापस आ जाता है जिसका उपयोग अंकों को कम करने के लिए किया जा सकता है। नीचे मेरा उदाहरण देखें।
जेफरी इवांस

एक बहुत भूमि के ऊपर का? यह अनिवार्य रूप से सिर्फ SpatialPolygonsDataFrame ऑब्जेक्ट से @ पॉलीगॉन स्लॉट ले रहा है। आप एक SpatialPolygonsDataFrame के वर्ग को "SpatialPolygons" होने के लिए आश्वस्त करके भी इसे 'नकली' कर सकते हैं (हालाँकि यह हैकी है और अनुशंसित नहीं है)। कुछ भी जो ज्यामिति का उपयोग करने वाला है, उस स्लॉट को किसी भी स्तर पर प्राप्त करना होगा, इसलिए अपेक्षाकृत इसके ओवरहेड बिल्कुल नहीं बोल रहा है। इसका महत्व वैसे भी किसी भी वास्तविक दुनिया के अनुप्रयोग में है जहाँ आप तब बिंदु-बहुभुज परीक्षणों का भार उठाने जा रहे हैं।
स्पेसमैन

ओवरहेड के लिए लेखांकन में गति से अधिक विचार है। आर नाम स्थान में एक नई वस्तु बनाने में आप आवश्यक रैम का उपयोग कर रहे हैं। जहां यह एक छोटे डेटासेट में कोई समस्या नहीं है, यह बड़े डेटा के साथ प्रदर्शन को प्रभावित करेगा। R लीनियर परफॉरमेंस को डाई ऑफ प्रदर्शित करता है। डेटा बड़ा हो जाता है के रूप में प्रदर्शन एक डिंग लेता है। यदि आपको एक अतिरिक्त ऑब्जेक्ट बनाने की आवश्यकता नहीं है, तो आप क्यों करेंगे?
जेफरी इवांस

1
हमें नहीं पता था कि जब तक मैंने इसे अभी परीक्षण नहीं किया था।
स्पैनमैन

13

sp ओपी उदाहरण के बाद स्थानिक चौराहे के आधार पर सुविधाओं का चयन करने के लिए एक छोटा रूप प्रदान करता है:

pts[ply,]

के रूप में:

points(pts[ply,], col = 'red')

पर्दे के पीछे के लिए यह छोटा है

pts[!is.na(over(pts, geometry(ply))),]

ध्यान देने वाली बात यह है कि एक geometryतरीका है जो विशेषताओं को गिराता है: overव्यवहार को बदलता है अगर उसके दूसरे तर्क में विशेषताएँ हैं या नहीं (यह ओपी का भ्रम था)। यह सभी स्थानिक * वर्गों के पार काम करता है sp, हालांकि कुछ overतरीकों की आवश्यकता होती है rgeos, विवरण के लिए इस विगनेट को देखें, उदाहरण के लिए बहुभुज को ओवरलैप करने के लिए कई मैचों का मामला।


जानकार अच्छा लगा! मुझे ज्यामिति विधि की जानकारी नहीं थी।
जेफरी इवांस

2
हमारी साइट में आपका स्वागत है, एडज़र - आपको यहाँ देखना अच्छा है!
whuber

1
धन्यवाद बिल - यह stat.ethz.ch/pipermail/r-sig-geo पर और अधिक शांत हो रहा है , या शायद हमें ऐसा सॉफ़्टवेयर विकसित करना चाहिए जो अधिक परेशानी का कारण बनता है! ;-)
एडज़र पेबस्मा

6

आप ओवर के साथ सही रास्ते पर थे। लौटे हुए ऑब्जेक्ट की पंक्तिनाम बिंदुओं की पंक्ति सूचकांक के अनुरूप हैं। आप कोड के कुछ अतिरिक्त लाइनों के साथ अपने सटीक दृष्टिकोण को लागू कर सकते हैं।

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

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

# Subset points intersecting polygon
prid <- over(pts,ply)
  ptid <- na.omit(prid) 
    pt.poly <- pts[as.numeric(as.character(row.names(ptid))),]  

plot(pts)
  axis(1); axis(2)
    plot(ply, add=TRUE, border="red")
      plot(pt.poly,pch=19,add=TRUE) 

गलत - लौटी हुई वस्तु की पंक्ति नाम पंक्ति अनुक्रमणिका in_this_case से मेल खाती है - सामान्य रूप से पंक्ति नाम बिंदुओं की पंक्ति नाम प्रतीत होते हैं - जो कि संख्यात्मक भी नहीं हो सकते हैं। आप एक चरित्र मिलान करने के लिए अपने समाधान को संशोधित कर सकते हैं जो इसे थोड़ा और मजबूत बना सकता है।
स्पेन्डमैन

@ सपेडमैन, इतने हठधर्मी मत बनो। समाधान गलत नहीं है। यदि आप पॉलीगनों के एक सेट के लिए बिंदुओं को कम करना चाहते हैं या बहुभुज मूल्यों को बिना किसी जबरदस्ती के कार्य करना चाहते हैं। एक बार जब आप ऑब्जेक्ट पर परिणाम प्राप्त कर लेते हैं तो एकाधिक को क्रॉसवाक करना होता है। आप एक स्पैटियलपॉलिगो ऑब्जेक्ट के साथ जबरदस्ती करने का समाधान काफी आवश्यक ओवरहेड बनाता है क्योंकि यह ऑपरेशन सीधे स्पैटियलपॉलीगैगनडैटाफ्रेम ऑब्जेक्ट पर किया जा सकता है। वैसे किसी पोस्ट को संपादित करने से पहले सुनिश्चित कर लें कि आप सही हैं। लाइब्रेरी और पैकेज शब्द का परस्पर विनिमय आर। में किया जाता है
जेफरी इवांस

मैंने अपनी पोस्ट में कुछ बेंचमार्क जोड़े हैं, और अपने फ़ंक्शन के साथ एक और समस्या देखी है। इसके अलावा "संकुल आर फ़ंक्शन, डेटा और संकलित कोड को एक अच्छी तरह से परिभाषित प्रारूप में संग्रहित करते हैं। जिस निर्देशिका में पैकेज संग्रहीत किए जाते हैं उसे पुस्तकालय कहा जाता है"
स्पेन्डमैन

जबकि आप "पैकेज" बनाम "लाइब्रेरी" के बारे में तकनीकी रूप से सही हैं, आपके तर्क शब्दार्थ हैं। मेरे पास सिर्फ एक पारिस्थितिक मॉडलिंग संपादक का अनुरोध था कि हम "पैकेज" (जो वास्तव में मेरी प्राथमिकता है) के हमारे उपयोग को "लाइब्रेरी" में बदल दें। मेरा कहना है कि वे विनिमेय शब्द और वरीयता की बात बन रहे हैं।
जेफरी इवांस

1
डॉ। शेल्डन कूपर के रूप में "तकनीकी रूप से सही" एक बार टिप्पणी की, "सही का सबसे अच्छा प्रकार है"। वह संपादक तकनीकी रूप से गलत है, जो कि सबसे खराब प्रकार है।
स्पैनमैन

4

क्या यह आप के बाद है?

एक नोट, संपादन पर: apply()मनमाने ढंग से SpatialPolygonsवस्तुओं के साथ इस काम को करने के लिए रैपिंग कॉल की आवश्यकता होती है , जिसमें संभवतः एक से अधिक बहुभुज विशेषता होती है। मुझे इसे और अधिक सामान्य मामले में कैसे लागू किया जाए, इसका प्रदर्शन करने के लिए @Spacedman को धन्यवाद।

library(rgeos)
pp <- pts[apply(gIntersects(pts, ply, byid=TRUE), 2, any),]


## Confirm that it works
pp[1:5,]
#              coordinates       var1 var2
# 2 (-0.583205, -0.877737) 0.04001092    v
# 3   (0.394747, 0.702048) 0.58108350    v
# 5    (0.7668, -0.946504) 0.85682609    q
# 6    (0.31746, 0.641628) 0.13683264    y
# 9   (-0.469015, 0.44135) 0.13968804    m

plot(pts)
plot(ply, border="red", add=TRUE)
plot(pp, col="red", add=TRUE)

यदि plyएक से अधिक फीचर हैं, तो बुरी तरह से विफल हो जाता है, क्योंकि gIntersectsप्रत्येक सुविधा के लिए एक पंक्ति के साथ एक मैट्रिक्स लौटाता है। आप शायद TRUE मान के लिए पंक्तियों को स्वीप कर सकते हैं।
स्पैनमैन

@ शालीन व्यक्ति - बिंगो। करने की जरूरत है apply(gIntersects(pts, ply, byid=TRUE), 2, any)। वास्तव में, मैं आगे बढ़ूंगा और इसका उत्तर स्विच करूंगा, क्योंकि यह एक एकल बहुभुज के मामले को भी शामिल करता है।
जोश ओ'ब्रायन

आह any,। हो सकता है कि मैं अभी बेंचमार्क किए गए संस्करण की तुलना में थोड़ा तेज हो।
स्पैनमैन

@Spacedman - मेरे त्वरित परीक्षणों से, ऐसा लगता है obrienऔर rowlings2गर्दन और गर्दन को चलाते हैं, obrien शायद 2% तेजी से।
जोश ओ'ब्रायन

@ JoshO'Brien कोई भी कई बहुभुजों पर इस उत्तर का उपयोग कैसे कर सकता है? यह एक ppहोना चाहिए IDजो इंगित करता है जिसमें बहुभुज अंक स्थित हैं।
कोड १२

4

यहां rgeosपैकेज का उपयोग करके एक संभव दृष्टिकोण दिया गया है। मूल रूप से, यह उस gIntersectionफ़ंक्शन का उपयोग करता है जो आपको दो spऑब्जेक्ट्स को इंटरसेक्ट करने की अनुमति देता है । बहुभुज के भीतर स्थित उन बिंदुओं की आईडी निकालने से, आप बाद में अपने मूल को कम करने में सक्षम होते हैं SpatialPointsDataFrame, जो सभी संबंधित डेटा रखते हैं। कोड लगभग आत्म-व्याख्यात्मक है, लेकिन यदि कोई प्रश्न हैं, तो कृपया बेझिझक पूछें!

# Required package
library(rgeos)

# Intersect polygons and points, keeping point IDs
pts.intersect <- gIntersection(ply, pts, byid = TRUE)

# Extract point IDs from intersected data
pts.intersect.strsplit <- strsplit(dimnames(pts.intersect@coords)[[1]], " ")
pts.intersect.id <- as.numeric(sapply(pts.intersect.strsplit, "[[", 2))

# Subset original SpatialPointsDataFrame by extracted point IDs
pts.extract <- pts[pts.intersect.id, ]

head(coordinates(pts.extract))
              x          y
[1,] -0.5832050 -0.8777367
[2,]  0.3947471  0.7020481
[3,]  0.7667997 -0.9465043
[4,]  0.3174604  0.6416281
[5,] -0.4690151  0.4413502
[6,]  0.4765213  0.6068021

head(pts.extract)
         var1 var2
2  0.04001092    v
3  0.58108350    v
5  0.85682609    q
6  0.13683264    y
9  0.13968804    m
10 0.97144627    o

1
होना tmpचाहिए pts.intersect? इसके अलावा, इस तरह से लौटे डिमनाम को पार्स करना अनैजंटेड बिहेवियर पर निर्भर करता है।
स्पेन्डमैन

@Spacedman, आप इसके बारे में सही हैं tmp, कोड खत्म करते समय इसे निकालना भूल गए। इसके अलावा, आप पार्स करने के बारे में सही हैं dimnames। यह प्रश्नकर्ता को त्वरित उत्तर प्रदान करने के लिए एक त्वरित समाधान था, और निश्चित रूप से बेहतर (और अधिक सार्वभौमिक) दृष्टिकोण हैं, उदाहरण के लिए तुम्हारा :-)
fdetsch

1

पुस्तकालय का उपयोग करते हुए एक अत्यंत सरल उपाय हैspatialEco

library(spatialEco)

# intersect points in polygon
  pts <- point.in.poly(pts, ply)

# check plot
  plot(ply)
  plot(a, add=T)

# convert to data frame, keeping your data
  pts<- as.data.frame(pts)

परिणाम की जाँच करें:

pts

>             x          y       var1 var2 polyvar
> 2  -0.5832050 -0.8777367 0.04001092    v     357
> 3   0.3947471  0.7020481 0.58108350    v     357
> 5   0.7667997 -0.9465043 0.85682609    q     357
> 6   0.3174604  0.6416281 0.13683264    y     357
> 9  -0.4690151  0.4413502 0.13968804    m     357
> 10  0.4765213  0.6068021 0.97144627    o     357
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.