Cách thích hợp để kiểm tra SpatialPolygonsDataFrames với ID đa giác giống hệt nhau?


22

Thành ngữ R thích hợp để gắn kết các SPDF với nhau khi các ID trùng nhau là gì? Lưu ý rằng ở đây (như thường lệ) các ID về cơ bản là vô nghĩa, vì vậy thật khó chịu khi tôi không thể khiến người khác bỏ qua chúng ....

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"

Câu trả lời:


15

ID, vị trí và chức năng loại áp dụng. Ba điều ít yêu thích nhất của tôi là hoàn toàn cần thiết cho mọi thứ tôi làm. Tôi nghĩ rằng tôi sẽ trả lời chỉ để tạo thêm nội dung về chủ đề này.

Mã dưới đây hoạt động, nhưng nó vẫn giữ các giá trị ID "vô dụng". Mã tốt hơn sẽ dành thời gian để phân tích mọi thứ sao cho mọi đường truyền đều có trạng thái Trin, hạt Trin và đường ống làm ID của nó. Chỉ cần thêm một vài dòng để thực hiện điều đó, nhưng vì bạn không quan tâm đến ID, chúng tôi sẽ loại bỏ ngay bây giờ.

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

Cảm ơn. Tôi đã có ý định kiểm tra điều này trong vài ngày nay nhưng cuộc sống đã can thiệp. Tôi hơi ngạc nhiên vì nhiều dòng mã này. Bạn có nghĩ rằng sẽ đáng để gửi một bản vá cho phương thức SPDF rbindtrong spgói không? Tôi đã nghĩ đến việc biến một cái gì đó giống như mã này thành một ,deduplicateIDs=TRUEđối số cho phương thức ....
Ari B. Friedman

Thực sự chỉ có ba dòng mã cho hàm và một dòng để áp dụng nó trước, nhưng phải mất một thời gian để xử lý vấn đề của bạn. Tôi luôn thấy việc xử lý ID trong SPDF là một vấn đề (bất cứ khi nào tôi tải thứ gì đó bằng rgdal chẳng hạn), nhưng dường như Roger Bivand luôn có thể khiến chúng hành xử nên tôi chỉ cho rằng đó là thiếu sót của riêng tôi. Tôi thích ý tưởng về một bản vá, nhưng tự hỏi nếu truy cập vào các khe đó sẽ gây ra các biến chứng cho những thứ khác trong sp.
csfowler

Câu trả lời chính xác. Chỉ muốn thêm một lời khuyên cho người khác rằng khi rbind bị kẹt trong mã của tôi, thường là do lỗi trước đó (dẫn đến ID trùng lặp). Vì vậy, lỗi là chính xác.
Chris

20

Đây là một cách tiếp cận thậm chí đơn giản hơn:

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

1
Tôi muốn điều này đã được ghi nhận trong trang trợ giúp của rbind. Tôi phải nhìn vào đây mỗi khi tôi không thể nhớ các quy tắc vỏ mà họ đã sử dụng cho lập luận này. Câu trả lời tốt nhất cho chắc chắn. Tôi không nghĩ rằng nó cần nhiều bối cảnh hơn và chắc chắn không nên xóa!
JMT2080AD

Tài liệu gợi ý "make.row.names = TRUE)" ... dường như không hoạt động. Sao chép-dán ví dụ đã làm.
Mox

Tôi nghĩ lý do điều này không được ghi lại trong trợ giúp là vì bạn đang thực hiện một cuộc gọi phương thức sp khi bạn truyền một đối tượng sp cho rbind. Xem methods(class = "SpatialLines"). Tôi không chắc về điều này nhưng đó là phỏng đoán tốt nhất của tôi ngay bây giờ. Tôi khá chắc chắn Edzer và co. không duy trì rbind chính nó, do đó thiếu tài liệu trong rbind.
JMT2080AD

Điều gì nếu có một danh sách dài các đối tượng để hợp nhất ( x1, x2, x3, ..., xn)? Có một phương pháp để nắm bắt toàn bộ danh sách mà không cần gõ tất cả chúng ra?
Phil

Chỉ hoạt động nếu số lượng cột bằng nhau.
Dennis

9

Được rồi, đây là giải pháp của tôi. Gợi ý chào mừng. Tôi có thể sẽ gửi bản này dưới dạng bản vá cho sptrừ khi bất kỳ ai nhìn thấy bất kỳ thiếu sót nào.

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

Tôi đã đánh giá cao chi tiết của các câu trả lời khác ở đây và, dựa trên chúng, lớp lót mà tôi đã đến nằm bên dưới. Giống như OP, tôi không quan tâm nhiều đến ý nghĩa của ID, nhưng những điều sau đây cũng có thể được điều chỉnh để nhúng ID thông tin hơn.

lst <- lapply(1:length(lst), function(i) spChFIDs(lst[[i]], paste0(as.character(i), '.', 1:length(lst[[i]]))))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.