동일한 폴리곤 ID로 SpatialPolygonsDataFrame을 리 바인드하는 올바른 방법은 무엇입니까?


22

ID가 겹칠 때 SPDF를 함께 바인딩하기위한 적절한 R 관용구는 무엇입니까? 여기서 (종종 경우와 같이) ID는 기본적으로 의미가 없으므로 rbind가 무시할 수 없다는 것은 상당히 성가신 일입니다 ....

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

ID, 슬롯 및 적용 유형 기능. 내가하는 모든 일에 절대적으로 필요한 가장 좋아하는 3 가지 가장 좋아하는 것들. 이 주제에 대해 더 많은 콘텐츠를 생성하기 위해 응답한다고 생각했습니다.

아래 코드는 작동하지만 "쓸모없는"ID 값을 유지합니다. 더 나은 코드는 모든 구역이 상태 FIPS, 카운티 FIPS 및 트랙 FIPS를 ID로 갖도록 구문 분석하는 데 시간이 걸립니다. 이를 위해 몇 줄만 더 추가해도되지만 ID에 신경 쓰지 않기 때문에 지금은 그대로 두겠습니다.

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

감사. 나는 며칠 동안 이것을 점검하고 싶었지만 인생은 개입했습니다. 이 많은 코드 줄에 놀랐습니다. 당신은의 SPDF 방법에 패치를 제출 가치가있을 것이라고 생각하십니까 rbindsp패키지? 나는이 코드 같은 것을 돌려 생각하고 있었는데 ,deduplicateIDs=TRUE.... 방법에 인수
아리 B. 프리드먼

실제로 함수에 대한 세 줄의 코드와 사전 리 바인드를 적용하는 코드이지만 문제를 처리하는 데 시간이 걸립니다. 나는 항상 SPDF에서 ID를 다루는 것이 문제라는 것을 알았지 만 (예를 들어 rgdal로 무언가를로드 할 때마다) Roger Bivand는 항상 그것들을 행동으로 만들 수있어 내 자신의 단점이라고 생각했습니다. 패치라는 아이디어가 마음에 들지만 해당 슬롯에 액세스하면 sp.
csfowler

좋은 대답입니다. rbind가 내 코드에 갇 히면 일반적으로 이전 실수 (중복 ID가 발생 함) 때문이라고 다른 사람들에게 조언을 추가하고 싶습니다. 따라서 오류가 맞습니다.
Chris

20

이것은 더 간단한 접근법입니다.

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

1
이것이 rbind 도움말 페이지에 문서화되어 있기를 바랍니다. 나는 그들이이 주장에 사용 된 케이싱 규칙을 기억할 수 없을 때마다 여기를 봐야한다. 최고의 답변입니다. 더 문맥이 필요하다고 생각하지 않으며 확실히 제거해서는 안됩니다!
JMT2080AD

문서에 따르면 "make.row.names = TRUE)"가 작동하지 않습니다. 예제를 복사하여 붙여 넣었습니다.
Mox

이것이 도움말에 문서화되어 있지 않은 이유는 sp 객체를 rbind에 전달할 때 sp 메소드 호출을하기 때문이라고 생각합니다. 참조하십시오 methods(class = "SpatialLines"). 나는 이것에 대해 확신하지 못하지만 그것은 지금 내 최선의 추측입니다. Edzer와 공동 확신합니다. rbind 자체를 유지 관리하지 않으므로 rbind에 문서가 부족합니다.
JMT2080AD

병합 할 객체 목록이 길면 x1, x2, x3, ..., xn어떻게됩니까 ( )? 전체 목록을 모두 입력하지 않고 전체 목록을 캡처하는 방법이 있습니까?
Phil

열 수가 동일한 경우에만 작동합니다.
Dennis

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

나는 여기에 다른 답변의 세부 사항을 높이 평가했으며, 그 답을 바탕으로 내가 얻은 하나의 라이너가 아래에 있습니다. OP와 마찬가지로 ID의 의미에 대해서는별로 신경 쓰지 않지만 다음은 더 유익한 ID를 포함하도록 조정할 수도 있습니다.

lst <- lapply(1:length(lst), function(i) spChFIDs(lst[[i]], paste0(as.character(i), '.', 1:length(lst[[i]]))))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.