SpatialPolygonsDataFrame'leri aynı çokgen kimlikleriyle ilişkilendirmenin doğru yolu?


22

ID'ler çakıştığında SPDF'leri bir araya getirmek için uygun R deyimi nedir? Burada (çoğu zaman olduğu gibi) kimlik numaralarının temel olarak anlamsız olduklarını unutmayın, bu yüzden onları rahatsız etmemem çok can sıkıcı.

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"

Yanıtlar:


15

Kimlikler, yuvalar ve uygulama tipi işlevleri. En iyi üç en sevdiğim şey, yaptığım her şey için kesinlikle gerekli. Bu konuda daha fazla içerik oluşturmak için cevap vereceğimi düşündüm.

Aşağıdaki kod çalışır, ancak “işe yaramaz” ID değerlerini korur. Daha iyi bir kod, her yolun FIPS, ilçe FIPS, ve FIPS'nin ID'si olması için her yolun ayrıştırılması için zaman harcardı. Bunu yapmak için birkaç satır daha var, ama kimliğinizi önemsemediğiniz için şimdilik bırakacağız.

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

Teşekkürler. Birkaç gündür bunu kontrol etmek istemiştim ama hayat müdahale etti. Bu kadar kod satırı olduğunu hayret ediyorum. Sen bunda SPDF yöntemine bir yama göndererek değer olacağını düşünüyor musunuz rbindiçinde sppaketin? Bu kod gibi bir şeyi ,deduplicateIDs=TRUEmetodun argümanına çevirmeyi düşünüyordum ....
Ari B. Friedman

Gerçekten sadece işlev için üç kod satırı ve bir tane daha ön-geri uygulayacak, ancak probleminizin işlenmesi biraz zaman alabilir. Her zaman SPDF'lerde kimliğin ele alınmasının bir sorun olduğunu her zaman buldum (mesela rgdal ile bir şey yüklediğimde), ancak Roger Bivand her zaman onların kendi davranışım olduğunu düşünerek her zaman kendi eksikliğim olduğunu varsaydım. Bir yama fikrini seviyorum, ancak bu yuvalara erişmenin sp.
csfowler 7:12

Mükemmel cevap. Sadece başkalarına rbind kodumda sıkışıp kaldığında, bunun genellikle daha önceki bir hatadan (yinelenen ID'ler ile sonuçlanır) kaynaklandığı konusunda bir tavsiye kelimesi eklemek istiyorum. Yani hata doğru.
Chris

20

Bu daha basit bir yaklaşımdır:

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

1
Bunun rbind yardım sayfasında belgelenmesini diliyorum. Bu tartışma için kullandıkları kasa kurallarını her zaman hatırlayamıyorum. Kesin olarak en iyi cevap. Daha fazla içeriğe ihtiyacı olduğunu sanmıyorum ve kesinlikle kaldırılmaması gerekiyor!
JMT2080AD

Belgeler, işe yaramış görünmeyen "make.row.names = TRUE)" ... önerdi. Örneği kopyalayıp yapıştırarak yaptım.
Mox

Bunun yardımda belgelenmemesinin sebebi, rbind için bir sp nesnesini geçtiğinizde bir sp yöntemi çağrısı yaptığınızdır. Bakın methods(class = "SpatialLines"). Bundan emin değilim, ama şu an için en iyi tahminim bu. Eminim Edzer ve co. geri sarmayı sürdürmüyor, dolayısıyla geri sarmada dokümantasyon eksikliği.
JMT2080AD

Birleşecek nesnelerin uzun bir listesi varsa ( x1, x2, x3, ..., xn)? Listeyi hepsini yazmadan yakalamak için bir yöntem var mı?
Phil

Yalnızca sütun sayısı eşitse çalışır.
Dennis

9

Tamam, işte çözümüm. Önerilerinizi bekliyoruz. spKimsenin göz kamaştırıcı ihmalleri görmediği sürece bunu bir yama olarak sunacağım .

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

Buradaki diğer cevapların detaylarını takdir ettim ve bunlara dayanarak, geldiğim tek astar aşağıda. OP gibi, kimliğin anlamı hakkında pek fazla umrumda değil, ancak aşağıdakiler de daha bilgilendirici bir kimlik yerleştirmek için uyarlanabilir.

lst <- lapply(1:length(lst), function(i) spChFIDs(lst[[i]], paste0(as.character(i), '.', 1:length(lst[[i]]))))
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.