समान बहुभुज ID के साथ SpatialPolygonsDataFrames को rbind करने का उचित तरीका?


22

IDs ओवरलैप होने पर SPDFs को एक साथ rbinding के लिए उचित R मुहावरा क्या है? ध्यान दें कि यहाँ (जैसा कि अक्सर होता है) आईडी मूल रूप से अर्थहीन होती है इसलिए यह बहुत कष्टप्रद है कि मैं सिर्फ rbb को अनदेखा नहीं कर सकता ...।

library(sp)
library(UScensus2000)
library(UScensus2000tract)

data(state) # for state names
states <- gsub( " ", "_", tolower(state.name) )
datanames <- paste(states,"tract", sep=".")
data( list=datanames )
lst <- lapply(datanames,get)

nation <- do.call( rbind, lst )
Error in validObject(res) : 
  invalid class SpatialPolygons object: non-unique Polygons ID slot values

# This non-exported function designed to solve this doesn't seem to work any more.
d <- sp:::makeUniqueIDs( list(arizona.tract,delaware.tract) )
Error in slot(i, "ID") : 
  no slot of name "ID" for this object of class "SpatialPolygonsDataFrame"

जवाबों:


15

आईडी के, स्लॉट, और लागू-प्रकार के कार्य। मेरी शीर्ष तीन कम से कम पसंदीदा चीजें जो मेरे लिए सब कुछ करने के लिए बिल्कुल आवश्यक हैं। मुझे लगा कि मैं इस विषय पर और अधिक सामग्री उत्पन्न करने के लिए प्रतिक्रिया दूंगा।

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

#Your Original Code
library(sp)
library(UScensus2000)
library(UScensus2000tract)

data(state) # for state names
states <- gsub( " ", "_", tolower(state.name) )
datanames <- paste(states,"tract", sep=".")
data( list=datanames )
lst <- lapply(datanames,get)

#All good up to here, but we need to create unique ID's before rbind

#Modified from Roger Bivand's response at:
# https://stat.ethz.ch/pipermail/r-sig-geo/2007-October/002701.html

#For posterity: We can access the ID in two ways:
class(alaska.tract)
getSlots(class(alaska.tract))
class(slot(alaska.tract, "polygons")[[1]])
getSlots(class(slot(alaska.tract, "polygons")[[1]]))

#So to get all ID's
sapply(slot(alaska.tract, "polygons"), function(x) slot(x, "ID"))
#or
rownames(as(alaska.tract, "data.frame"))
#These should be the same, but they are quite different...sigh. Doesn't matter for
#what follows though

#To make them uniform we can write a function using the spChFIDs function from sp:
makeUniform<-function(SPDF){
  pref<-substitute(SPDF)  #just putting the file name in front.
  newSPDF<-spChFIDs(SPDF,as.character(paste(pref,rownames(as(SPDF,"data.frame")),sep="_")))
  return(newSPDF)
}

#now to do this for all of our state files
newIDs<-lapply(lst,function(x) makeUniform(x))

#back to your code...
nation <- do.call( rbind, newIDs )

धन्यवाद। मैं अब कुछ दिनों के लिए इस पर जाँच करने का अर्थ कर रहा हूँ, लेकिन जीवन ने हस्तक्षेप किया है। मुझे आश्चर्य है कि यह कोड की कई लाइनें हैं। क्या आपको लगता rbindहै कि spपैकेज में SPDF विधि में एक पैच जमा करने लायक होगा ? मैं इस कोड को एक ,deduplicateIDs=TRUEविधि के तर्क में बदलने की सोच रहा था ....
अरी बी। फ्रीडमैन

फ़ंक्शन के लिए वास्तव में कोड की केवल तीन पंक्तियाँ और एक इसे पूर्व-आरबाइंड लागू करने के लिए, लेकिन आपकी समस्या के लिए प्रक्रिया में कुछ समय लगता है। मुझे हमेशा SPDF में आईडी की हैंडलिंग एक समस्या के रूप में मिली है (किसी भी समय मैं उदाहरण के लिए rgdal के साथ कुछ लोड करता हूं), लेकिन रोजर बिवांड हमेशा उन्हें व्यवहार करने में सक्षम लगता है इसलिए मैंने अभी यह मान लिया है कि यह मेरी खुद की कमी है। मुझे एक पैच का विचार पसंद है, लेकिन आश्चर्य है कि अगर उन स्लॉट्स को एक्सेस करने से सपा में अन्य चीजों के लिए जटिलताएं पैदा होंगी।
csfowler

बहुत बढ़िया जवाब। बस दूसरों को सलाह का एक शब्द जोड़ना चाहते हैं कि जब rbind मेरे कोड में फंस जाता है, तो यह आमतौर पर पहले की गलती (डुप्लिकेट आईडी के परिणामस्वरूप) के कारण होता है। तो त्रुटि सही है।
क्रिस

20

यह एक और भी सरल तरीका है:

x <- rbind(x1, x2, x3, makeUniqueIDs = TRUE)  

1
काश यह rbind सहायता पृष्ठ में प्रलेखित होता। मुझे हर बार यहाँ देखना होगा कि मैं इस तर्क के लिए उपयोग किए जाने वाले आवरण नियमों को याद नहीं कर सकता। यकीन के लिए सबसे अच्छा जवाब। मुझे नहीं लगता कि इसे अधिक संदर्भ की आवश्यकता है, और निश्चित रूप से इसे हटाया नहीं जाना चाहिए!
JMT2080AD

दस्तावेज़ीकरण से पता चलता है कि "make.row.names = TRUE)" ... जो काम नहीं करता है। उदाहरण को कॉपी-पेस्ट करना।
मोक्स

मुझे लगता है कि इसका कारण यह है कि मदद में दस्तावेज नहीं है, क्योंकि आप एक sp विधि कॉल कर रहे हैं जब आप rbind के लिए एक sp ऑब्जेक्ट पास करते हैं। देखते हैं methods(class = "SpatialLines")। मुझे इस पर यकीन नहीं है, लेकिन यह मेरा सबसे अच्छा अनुमान है। मुझे पूरा यकीन है कि एडज़र और सह। खुद को rbind बनाए नहीं रख रहे हैं, इसलिए rbind में प्रलेखन की कमी है।
JMT2080AD

क्या होगा यदि वस्तुओं की एक लंबी सूची को मर्ज किया जाए ( x1, x2, x3, ..., xn)? क्या उन सभी को टाइप किए बिना पूरी सूची पर कब्जा करने की कोई विधि है?
फिल

कॉलम की संख्या बराबर होने पर ही काम करता है।
डेनिस

9

ठीक है, यहाँ मेरा समाधान है। सुझाव का स्वागत करते हैं। मैं इसे एक पैच के रूप में प्रस्तुत करूँगा spजब तक कि कोई भी चमकता हुआ चूक नहीं देखता।

#' Get sp feature IDs
#' @aliases IDs IDs.default IDs.SpatialPolygonsDataFrame
#' @param x The object to get the IDs from
#' @param \dots Pass-alongs
#' @rdname IDs
IDs <- function(x,...) {
  UseMethod("IDs",x)
}
#' @method IDs default
#' @S3method IDs default
#' @rdname IDs
IDs.default <- function(x,...) {
  stop("Currently only SpatialPolygonsDataFrames are supported.")
}
#' @method IDs SpatialPolygonsDataFrame
#' @S3method IDs SpatialPolygonsDataFrame
#' @rdname IDs
IDs.SpatialPolygonsDataFrame <- function(x,...) {
  vapply(slot(x, "polygons"), function(x) slot(x, "ID"), "")
}

#' Assign sp feature IDs
#' @aliases IDs<- IDs.default<-
#' @param x The object to assign to
#' @param value The character vector to assign to the IDs
#' @rdname IDs<-
"IDs<-" <- function( x, value ) {
  UseMethod("IDs<-",x)
}
#' @method IDs<- SpatialPolygonsDataFrame
#' @S3method IDs<- SpatialPolygonsDataFrame
#' @rdname IDs<-
"IDs<-.SpatialPolygonsDataFrame" <- function( x, value) {
  spChFIDs(x,value)
}

#' rbind SpatialPolygonsDataFrames together, fixing IDs if duplicated
#' @param \dots SpatialPolygonsDataFrame(s) to rbind together
#' @param fix.duplicated.IDs Whether to de-duplicate polygon IDs or not
#' @return SpatialPolygonsDataFrame
#' @author Ari B. Friedman, with key functionality by csfowler on StackExchange
#' @method rbind.SpatialPolygonsDataFrame
#' @export rbind.SpatialPolygonsDataFrame
rbind.SpatialPolygonsDataFrame <- function(..., fix.duplicated.IDs=TRUE) {
  dots <- as.list(substitute(list(...)))[-1L]
  dots_names <- as.character(dots) # store names of objects passed in to ... so that we can use them to create unique IDs later on
  dots <- lapply(dots,eval)
  names(dots) <- NULL
  # Check IDs for duplicates and fix if indicated
  IDs_list <- lapply(dots,IDs)
  dups.sel <- duplicated(unlist(IDs_list))
  if( any(dups.sel) ) {
    if(fix.duplicated.IDs) {
      dups <- unique(unlist(IDs_list)[dups.sel])
      # Function that takes a SPDF, a string to prepend to the badID, and a character vector of bad IDs
      fixIDs <- function( x, prefix, badIDs ) {
        sel <-  IDs(x) %in% badIDs
        IDs(x)[sel] <- paste( prefix, IDs(x)[sel], sep="." )
        x
      }
      dots <- mapply(FUN=fixIDs , dots, dots_names, MoreArgs=list(badIDs=dups) )
    } else {
      stop("There are duplicated IDs, and fix.duplicated.IDs is not TRUE.")
    }
  }
  # One call to bind them all
  pl = do.call("rbind", lapply(dots, function(x) as(x, "SpatialPolygons")))
  df = do.call("rbind", lapply(dots, function(x) x@data))
  SpatialPolygonsDataFrame(pl, df)
}

1

मैंने यहाँ अन्य उत्तरों के विस्तार की सराहना की है और, उन पर निर्माण करते हुए, जो एक-लाइनर मैं आया हूं, वह नीचे है। ओपी की तरह, मुझे आईडी के अर्थ की अधिक परवाह नहीं है, लेकिन निम्नलिखित को अधिक जानकारीपूर्ण आईडी को एम्बेड करने के लिए भी अनुकूलित किया जा सकता है।

lst <- lapply(1:length(lst), function(i) spChFIDs(lst[[i]], paste0(as.character(i), '.', 1:length(lst[[i]]))))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.