কীভাবে স্প্যাটিয়ালপয়েন্টস ডেটা ফ্রেমের উপরে বহুভুজকে ওভারলে করবেন এবং এসপিডিএফ ডেটা সংরক্ষণ করবেন?


17

আমার কাছে SpatialPointsDataFrameকিছু অতিরিক্ত ডেটা রয়েছে। আমি একটি বহুভুজের অভ্যন্তরে points পয়েন্টগুলি বের করতে চাই এবং একই সাথে SPDFঅবজেক্ট এবং তার সম্পর্কিত ডেটা সংরক্ষণ করব ।

এখনও অবধি আমার ভাগ্য খুব কম ছিল এবং একটি সাধারণ আইডির মাধ্যমে মিলে যাওয়া এবং একত্রীকরণের আশ্রয় নিয়েছিলাম, তবে এটি কেবলমাত্র ব্যক্তিগত আইডিএস সহ ডেটা গ্রিড করে রেখেছি বলেই কাজ করে।

এখানে একটি দ্রুত উদাহরণ, আমি লাল বর্গাকার ভিতরে পয়েন্ট খুঁজছি looking

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
> 

gIntersectsসি কোডের পরিবর্তে আর-তে ছেদগুলি পরীক্ষা করতে ম্যাট্রিক্স সুইপ করেও বুট দ্রুত হয়। আমি এটি সন্দেহprepared geometry জিওএস দক্ষতা , স্থানিক সূচক তৈরি করে - হ্যাঁ, এর সাথেprepared=FALSE এটি কিছুটা দীর্ঘ সময় নেয়, প্রায় 5.5 সেকেন্ডের মধ্যে।

আমি অবাক হয়েছি সূচকগুলি বা পয়েন্টগুলি সরাসরি ফেরত দেওয়ার জন্য কোনও ফাংশন নেই। আমি যখন splancs20 বছর আগে লিখেছিলাম পয়েন্ট-ইন-বহুভুজ ফাংশন দুটি ছিল ...


দুর্দান্ত, এটি একাধিক বহুভুজের জন্যও কাজ করে (আমি জোশুয়ার জবাব দিয়ে খেলতে উদাহরণ যোগ করেছি)।
রোমান Luštrik

একটি স্পিটিয়ালপলিগনস অবজেক্টে বৃহত বহুভিত্তিক ডেটাসেট জবরদস্তি সহ অনেকগুলি ওভারহেড এবং প্রয়োজনীয় নয়। একটি স্পেশিয়ালপলিগনস ডেটাফ্রেমে "ওভার" প্রয়োগ করা সারি সূচকটি দেয় যা পয়েন্টগুলি সাবসেট করতে ব্যবহার করা যেতে পারে। নীচে আমার উদাহরণ দেখুন।
জেফরি ইভান্স

একজন অনেক ওভারহেড এর? এটি কেবলমাত্র স্পটিয়ালপলিগনসডাটা ফ্রেম অবজেক্ট থেকে @ পলিজাগন স্লট নিচ্ছে। এমনকি আপনি এটি স্প্যাটিয়ালপলিজোনস ডেটা ফ্রেমের ক্লাসটিকে "স্প্যাটিয়ালপলিগনস" হিসাবে পুনর্নির্দিষ্ট করে 'জাল' করতে পারেন (যদিও এটি হ্যাকি এবং প্রস্তাবিত নয়)। যে কোনও কিছু জ্যামিতিটি ব্যবহার করতে চলেছে যে কোনওভাবে যে কোনও পর্যায়ে সেই স্লটটি পেতে হবে, তাই তুলনামূলকভাবে এর কোনও ওভারহেডের কথা বলার অপেক্ষা রাখে না। আপনি যে কোনও বাস্তব-বিশ্বের অ্যাপ্লিকেশনটিতে এর তুচ্ছতা হ'ল যেখানে আপনি তারপরে পয়েন্ট-বহুভুজ পরীক্ষা করতে যাচ্ছেন।
স্পেসডম্যান

ওভারহেডের জন্য অ্যাকাউন্টিংয়ের ক্ষেত্রে গতির বিবেচনার চেয়ে আরও বেশি কিছু রয়েছে। আর নেমস্পেসে একটি নতুন অবজেক্ট তৈরি করার সময় আপনি প্রয়োজনীয় র‌্যাম ব্যবহার করছেন। এটি একটি ছোট ডেটাসেটে সমস্যা না হলে এটি বড় ডেটা সহ কর্মক্ষমতা প্রভাবিত করবে। আর লিনিয়ার পারফরম্যান্সটি ডাই অফ করে দেয় R ডেটা বড় হওয়ার সাথে সাথে ডিংস লাগে। আপনার যদি কোনও অতিরিক্ত অবজেক্ট তৈরি করার দরকার না হয় তবে আপনি কেন করবেন?
জেফরি ইভান্স

1
আমি এখনই এটি পরীক্ষা না করা পর্যন্ত আমরা জানতাম না।
স্পেসডম্যান

13

sp ওপি উদাহরণ অনুসরণ করে স্থানিক ছেদ ভিত্তিতে বৈশিষ্ট্য নির্বাচন করতে একটি সংক্ষিপ্ত ফর্ম সরবরাহ করে:

pts[ply,]

হিসাবে:

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

নেপথ্যে এই জন্য সংক্ষিপ্ত

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

লক্ষ্য করার বিষয়টি হ'ল একটি geometryপদ্ধতি রয়েছে যা অ্যাট্রিবিউটসকে ড্রপ করে: overএর দ্বিতীয় যুক্তির বৈশিষ্ট্যগুলি আছে বা না থাকলে আচরণ পরিবর্তন করে (এটি ছিল ওপি'র বিভ্রান্তি)। এটি সমস্ত স্পেসিয়াল * ক্লাসগুলিতে কাজ করে sp, যদিও কিছু overপদ্ধতির প্রয়োজন হয় rgeos, বিশদটির জন্য এই চিত্রটি দেখুন, যেমন বহুভুজকে ওভারল্যাপ করার জন্য একাধিক ম্যাচের ক্ষেত্রে।


জানা ভাল! আমি জ্যামিতি পদ্ধতি সম্পর্কে অবগত ছিলাম না।
জেফ্রি ইভান্স

2
আমাদের সাইটে আপনাকে স্বাগতম, এডজার - আপনাকে এখানে দেখে ভাল লাগল!
হোবার

1
ধন্যবাদ বিল - এটি স্টেট.টিজ.সিচ / পিপারমেল / আর- সিগ- জিও সম্পর্কে আরও শান্ত হচ্ছে , বা সম্ভবত আমাদের এমন সফ্টওয়্যার তৈরি করা উচিত যা আরও বেশি সমস্যার সৃষ্টি করে! ;-)
এডজার পেবেসমা

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) 

ভুল - প্রত্যাবর্তিত অবজেক্টের রোমনামগুলি সারি সূচক ইন_থিস_ কেসের সাথে মিলে যায় - সাধারণভাবে সারিগুলির নামগুলি পয়েন্টগুলির সারি নাম বলে মনে হয় - যা সংখ্যাসূচকও নাও হতে পারে। একটি চরিত্রের মিল করতে আপনি নিজের সমাধানটি পরিবর্তন করতে পারেন যা এটি আরও দৃ bit় করতে পারে।
স্পেসডম্যান

@ সাপসিডম্যান, এতটা কৌতূহলবিহীন হবেন না। সমাধানটি ভুল নয়। আপনি যদি বহুভুজগুলির সেটগুলিতে পয়েন্টগুলি সাবসেট করতে চান বা বহুবিধ মানগুলি নির্ধারণ করতে চান তবে ওভার ফাংশনটি জোর করে ছাড়াই কাজ করে। একাধিকটি ক্রসওয়াকটি সম্পাদন করতে হবে যখন আপনি ফলাফলের ওভার অবজেক্টটি পেয়ে যান। আপনি একটি স্প্যাটিয়ালপলিগন অবজেক্টে জবরদস্তির সমাধান যথেষ্ট প্রয়োজনীয় ওভারহেড তৈরি করেন কারণ এই অপারেশনটি স্পেশালপলিজোনডাটা ফ্রেম অবজেক্টে সরাসরি সম্পাদন করা যায়। যাইহোক আপনি কোনও পোস্ট সম্পাদনা করার আগে নিশ্চিত হয়ে নিন যে আপনি ঠিক আছেন। শব্দটি লাইব্রেরি এবং প্যাকেজটি আর.
জেফ্রি ইভানস

আমি আমার পোস্টে কিছু মানদণ্ড যুক্ত করেছি এবং আপনার ক্রিয়াকলাপে আরও একটি সমস্যা চিহ্নিত করেছি। এছাড়াও "প্যাকেজগুলি একটি ভাল-সংজ্ঞায়িত ফর্ম্যাটে আর ফাংশন, ডেটা এবং সংকলিত কোডের সংগ্রহ। ডিরেক্টরিটি যেখানে প্যাকেজগুলি সংরক্ষণ করা হয় তাকে গ্রন্থাগার বলা হয়"
স্পেসডম্যান

আপনি যখন "প্যাকেজ" বনাম "লাইব্রেরি" সম্পর্কিত প্রযুক্তিগতভাবে সঠিক হন তবে আপনার যুক্তিবাদী শব্দার্থবিজ্ঞান রয়েছে। আমার সবেমাত্র একটি ইকোলজিকাল মডেলিং সম্পাদকের অনুরোধ ছিল যে আমরা আমাদের "প্যাকেজ" (যা আসলে আমার পছন্দ) এর ব্যবহারটি "লাইব্রেরিতে" পরিবর্তন করতে পারি। আমার বক্তব্যটি হ'ল এগুলি বিনিময়যোগ্য পদ এবং পছন্দসই বিষয় হয়ে উঠছে।
জেফরি ইভান্স

1
"প্রযুক্তিগতভাবে সঠিক" ডাঃ শেল্ডন কুপার যেমন একবার মন্তব্য করেছিলেন, "সঠিকভাবে সঠিক ধরণের"। এই সম্পাদকটি প্রযুক্তিগতভাবে ভুল, যা সবচেয়ে খারাপতম ধরণের।
স্পেসডম্যান

4

আপনি কি এই পরে?

একটি নোট, সম্পাদনাতে: apply()এই কাজটি স্বেচ্ছাসেবী SpatialPolygonsবস্তুগুলির সাথে তৈরি করার জন্য র্যাপিং কলটি প্রয়োজন , সম্ভবত একাধিক বহুভুজ বৈশিষ্ট্য রয়েছে। কীভাবে আরও সাধারণ ক্ষেত্রে এটি প্রয়োগ করা যায় তা প্রদর্শনের জন্য আমাকে স্পিডম্যানকে ধন্যবাদ জানাতে ধন্যবাদ।

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প্রতিটি বৈশিষ্ট্যের জন্য একটি সারি সহ একটি ম্যাট্রিক্স প্রদান করে। আপনি সম্ভবত একটি সত্য মানের জন্য সারিগুলি ঝাড়িয়ে দিতে পারেন।
স্পেসডম্যান

@ স্পিডম্যান - বিঙ্গো করতে হবে apply(gIntersects(pts, ply, byid=TRUE), 2, any)। আসলে, আমি এগিয়ে যাব এবং এর উত্তরটি স্যুইচ করব, যেহেতু এটি একটি একক বহুভুজের ক্ষেত্রেও অন্তর্ভুক্ত রয়েছে।
জোশ ওব্রায়ান

আহ any,। আমি সবেমাত্র বেঞ্চমার্ক করা সংস্করণটির তুলনায় এটি সামান্য দ্রুত হতে পারে।
স্পেসডম্যান

@ স্পিডম্যান - আমার দ্রুত পরীক্ষাগুলি থেকে মনে হচ্ছে এটি 2% দ্রুত হতে পারে obrienএবং rowlings2ঘাড় এবং ঘাড়ে চালাচ্ছে । obrien
জোশ ও'ব্রায়েন

@ জোশ'ব্রায়েন কীভাবে এই বহু উত্তর বহুবিধে ব্যবহার করতে পারেন? এটিতে একটি ppহওয়া উচিত IDযা নির্দেশ করে যে বহুভুজ পয়েন্টগুলি অবস্থিত।
123

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? এছাড়াও, প্রত্যাশিত আচরণের উপর নির্ভর করে এর মতো প্রত্যাবর্তিত ডিমনেমগুলি পার্স করা।
স্পেসডম্যান

@ স্পিডম্যান, আপনি ঠিক বলেছেন 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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.