Skip to content

Commit

Permalink
add knn to shape2mat
Browse files Browse the repository at this point in the history
  • Loading branch information
ConnorDonegan committed May 9, 2024
1 parent 6e61ee2 commit f57cc0f
Show file tree
Hide file tree
Showing 83 changed files with 1,200 additions and 299 deletions.
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: geostan
Title: Bayesian Spatial Analysis
Version: 0.6.0
Date: 2024-04-04
Version: 0.6.1
Date: 2024-05-08
URL: https://connordonegan.github.io/geostan/
BugReports: https://github.com/ConnorDonegan/geostan/issues
Authors@R: c(
Expand Down
7 changes: 5 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# geostan 0.6.1

- Visualizing spatial neighbors: `geostan::edges` can now return a simple features object for plotting the connections in the spatial connectivity matrix.
-
There are three updates, all related to spatial connectivity matrices:

- There is a new vignette on spatial connectivity matrices (see `browseVignettes('geostan')`), written for new users.
- Visualizing spatial neighbors: `geostan::edges` can now return a simple features object; this can be used to visualize (map) the graph structure of the spatial connectivity matrix.
- Changes to `geostan::shape2mat`: an option for k-nearest neighbors has been added, the `queen` argument is being replaced by `method`, and the function now prints a summary of the matrix to the console (using the new `geostasn::n_nbs` function)

# geostan 0.6.0

Expand Down
82 changes: 56 additions & 26 deletions R/convenience-functions.R
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ sim_sar <- function(m = 1, mu = rep(0, nrow(w)), w, rho, sigma = 1, ...) {
return(x)
}

#' Spatial data diagnostics
#' Visual displays of spatial data and spatial models
#'
#' @description Visual diagnostics for areal data and model residuals
#'
Expand Down Expand Up @@ -331,7 +331,7 @@ sp_diag.numeric <- function(y,
}


#' Data model diagnostics
#' Measurement error model diagnostics
#'
#' @description Visual diagnostics for spatial measurement error models.
#'
Expand Down Expand Up @@ -572,9 +572,15 @@ make_EV <- function(C, nsa = FALSE, threshold = 0.2, values = FALSE) {
#'
#' @param style What kind of coding scheme should be used to create the spatial connectivity matrix? Defaults to "B" for binary; use "W" for row-standardized weights.
#'
#' @param queen Passed to \code{\link[spdep]{poly2nb}} to set the contiguity condition. Defaults to \code{TRUE} so that a single shared boundary point (rather than a shared border/line) between polygons is sufficient for them to be considered neighbors.
#' @param queen Deprecated: use the `method' argument instead. This option is passed to \code{\link[spdep]{poly2nb}} to set the contiguity condition. Defaults to \code{TRUE} so that a single shared boundary point (rather than a shared border/line) between polygons is sufficient for them to be considered neighbors.
#'
#' @param method Method for determining neighbors: queen, rook, or k-nearest neighbors. See Details for more information.
#'
#' @param k Number of neighbors to select for k-nearest neighbor method. Passed to `spdep::knearneigh`.
#'
#' @param longlat If longlat = TRUE, Great Circle (rather than Euclidean) distances are used; great circle circle distances account for curvature of the Earth.
#'
#' @param snap Passed to \code{\link[spdep]{poly2nb}}; "boundary points less than ‘snap’ distance apart are considered to indicate contiguity."
#' @param snap Passed to `spdep::poly2nb`; "boundary points less than ‘snap’ distance apart are considered to indicate contiguity."
#'
#' @param t Number of time periods. Only the binary coding scheme is available for space-time connectivity matrices.
#'
Expand All @@ -588,6 +594,8 @@ make_EV <- function(C, nsa = FALSE, threshold = 0.2, values = FALSE) {
#'
#' @details
#'
#' The method argument currently has three options. The queen contiguity condition defines neighbors as polygons that share at least one point with one another. The rook condition requires that they share a line or border with one another. K-nearest neighbors is based on distance between centroids. All methods are implemented using the spdep package and then converted to sparse matrix format.
#'
#' Haining and Li (Ch. 4) provide a helpful discussion of spatial connectivity matrices (Ch. 4).
#'
#' The space-time connectivity matrix can be used for eigenvector space-time filtering (\code{\link[geostan]{stan_esf}}. The `lagged' space-time structure connects each observation to its own past (one period lagged) value and the past value of its neighbors. The `contemporaneous' specification links each observation to its neighbors and to its own in situ past (one period lagged) value (Griffith 2012, p. 23).
Expand All @@ -604,23 +612,23 @@ make_EV <- function(C, nsa = FALSE, threshold = 0.2, values = FALSE) {
#' data(georgia)
#'
#' ## binary adjacency matrix
#' C <- shape2mat(georgia, "B")
#' C <- shape2mat(georgia, "B", method = 'rook')
#'
#' ## number of neighbors per observation
#' summary( n_nbs(C) )
#' head(Matrix::summary(C))
#'
#' ## row-standardized matrix
#' W <- shape2mat(georgia, "W")
#' W <- shape2mat(georgia, "W", method = 'rook')
#'
#' ## summary of weights
#' E <- edges(W, unique_pairs_only = FALSE)
#' summary(E$weight)
#'
#'
#' ## space-time matricies
#' ## for eigenvector space-time filtering
#' ## if you have multiple years with same neighbors,
#' ## provide the geography (for a single year!) and number of years \code{t}
#' ## if you have multiple years with same geometry/geography,
#' ## provide the geometry (for a single year!) and number of years \code{t}
#' Cst <- shape2mat(georgia, t = 5)
#' dim(Cst)
#' EVst <- make_EV(Cst)
Expand All @@ -632,22 +640,43 @@ make_EV <- function(C, nsa = FALSE, threshold = 0.2, values = FALSE) {
#'
shape2mat <- function(shape,
style = c("B", "W"),
queen = TRUE,
queen,
method = c('queen', 'rook', 'knn'),
k = 1,
longlat = NULL,
snap = sqrt(.Machine$double.eps),
t = 1,
st.style = c("contemp", "lag"),
quiet = FALSE
)
{
style <- match.arg(style)
style <- match.arg(style)
method <- match.arg(method)
st.style <- match.arg(st.style)
nb <- spdep::poly2nb(shape, queen = queen, snap = snap)
ids <- 1:nrow(shape)
dims <- rep(length(ids), 2)
Ni <- unlist(lapply(nb, count_neighbors))
i <- rep(ids, times = Ni)
j <- do.call("c", nb)
j <- j[j>0]
## temporary: handle deprecation of queen
if (!missing(queen)) {
message("The 'queen' argument is deprecated. Use 'method' instead.")
if (queen == TRUE) method <- 'queen'
if (queen == FALSE) method <- 'rook'
} else {
queen <- ifelse(method == 'queen', TRUE, FALSE)
}
##
N <- nrow(shape)
ids <- 1:N
dims <- rep(N, 2)
if (method == "knn") {
coords <- sf::st_centroid(sf::st_geometry(shape), of_largest_polygon=TRUE)
nb <- spdep::knearneigh(coords, k = k, longlat = longlat)$nn
i <- rep(ids, each = k)
j <- c(t(nb))
} else {
nb <- spdep::poly2nb(shape, queen = queen, snap = snap)
Ni <- unlist(lapply(nb, count_neighbors))
i <- rep(ids, times = Ni)
j <- do.call("c", nb)
j <- j[j>0]
}
stopifnot(length(i) == length(j))
C <- Matrix::sparseMatrix(i = i, j = j, dims = dims)
if (style == "W") C <- row_standardize(C, warn = FALSE)
Expand All @@ -666,8 +695,8 @@ shape2mat <- function(shape,
}
}
if (!quiet) {
cond <- ifelse(queen == TRUE, "Queen", "Rook")
message(paste0("Contiguity condition: ", cond))
if (method == 'knn') method <- paste0('knn, k=', k)
message(paste0("Contiguity condition: ", method))
Ni <- n_nbs(C)
message("Number of neighbors per unit, summary:")
print(summary(Ni))
Expand Down Expand Up @@ -770,8 +799,9 @@ waic <- function(fit, pointwise = FALSE, digits = 2) {
#' @return A vector with the number of non-zero values in each row of `C`
#'
#' @examples
#'
#' data(sentencing)
#' C <- shape2mat(C)
#' C <- shape2mat(sentencing)
#' sentencing$Ni <- n_nbs(C)
#'
#' @export
Expand Down Expand Up @@ -813,7 +843,7 @@ n_nbs <- function(C) {
#'
#' ## add geometry for plotting
#' library(sf)
#' E <- edges(C, spatial = sentencing)
#' E <- edges(C, shape = sentencing)
#' g1 = st_geometry(E)
#' g2 = st_geometry(sentencing)
#' plot(g1, lwd = .2)
Expand All @@ -824,7 +854,7 @@ n_nbs <- function(C) {
#' @importFrom sf st_point_on_surface st_linestring st_sfc st_as_sf st_crs
#'
#' @export
edges <- function(C, unique_pairs_only = TRUE, spatial) {
edges <- function(C, unique_pairs_only = TRUE, shape) {
stopifnot(inherits(C, "Matrix") | inherits(C, "matrix"))
edges <- Matrix::summary(Matrix::Matrix(C))
names(edges)[1:2] <- c("node1", "node2")
Expand All @@ -838,14 +868,14 @@ edges <- function(C, unique_pairs_only = TRUE, spatial) {
if (unique_pairs_only) edges <- edges[which(edges$node1 < edges$node2),]
rownames(edges) <- NULL
class(edges) <- "data.frame"
if (missing(spatial)) return(edges)
geos = suppressWarnings(sf::st_point_on_surface(sentencing)$geometry )
if (missing(shape)) return(edges)
geos = suppressWarnings(sf::st_geometry(sf::st_point_on_surface(shape)) )
lines <- lapply(1:nrow(edges), FUN = function(j) {
sf::st_linestring( c(geos[[ edges$node1[j] ]], geos[[ edges$node2[j] ]]) )
})
geo_ls <- sf::st_sfc(lines)
df <- cbind(edges, geo_ls)
nbs_st <- sf::st_as_sf(df, crs = sf::st_crs(spatial))
nbs_st <- sf::st_as_sf(df, crs = sf::st_crs(shape))
return (nbs_st)
}

Expand Down
2 changes: 1 addition & 1 deletion R/geostan-package.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#'
#' @description Bayesian spatial modeling powered by Stan. **geostan** provides access to a variety of hierarchical spatial models using the R formula interface, supporting a complete spatial analysis workflow with a suite of spatial analysis tools. It is designed primarily for public health and social science research but is generally applicable to modeling areal data. Unique features of the package include its spatial measurement error model (for inference with small area estimates such as those from the American Community Survey), its fast proper conditional autoregressive (CAR) and simultaneous autoregressive (SAR) models, and its eigenvector spatial filtering (ESF) models. The package also supports spatial regression with raster layers.
#'
#' @docType _PACKAGE
#' @docType package
#' @name geostan-package
#' @aliases geostan
#' @useDynLib geostan, .registration = TRUE
Expand Down
4 changes: 2 additions & 2 deletions R/moran.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

#' The Moran coefficient
#' The Moran coefficient (Moran's I)
#'
#' @description The Moran coefficient, a measure of spatial autocorrelation (also known as Global Moran's I)
#'
Expand Down Expand Up @@ -59,7 +59,7 @@ mc <- function(x, w, digits = 3, warn = TRUE, na.rm = FALSE) {
return(round(mc, digits = digits))
}

#' Moran plot
#' Moran scatter plot
#'
#' @description Plots a set of values against their spatially lagged values and gives the Moran coefficient as a measure of spatial autocorrelation.
#'
Expand Down
2 changes: 1 addition & 1 deletion R/raster-analysis.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#' Eigenvalues of a spatial weights matrix: raster analysis
#' Eigenvalues of a spatial weights matrix: for spatial regression with raster data
#'
#' @description Approximate eigenvalues for the row-standardized spatial connectivity matrix W of a regular tessellation, e.g., remotely sensed imagery.
#'
Expand Down
47 changes: 22 additions & 25 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,52 @@ home:
articles:
- title: "Package vignettes"
contents:
- custom-spatial-models
- spatial-weights-matrix
- measuring-sa
- raster-regression
- custom-spatial-models
- spatial-me-models
- raster-regression
reference:
- title: "Package overview"
- contents:
- geostan-package
- title: "Spatial analysis"
desc: Functions for measuring and visualizing spatial autocorrelation and dispersion, including model diagnostics
- title: "Spatial data"
- contents:
- edges
- get_shp
- make_EV
- n_nbs
- row_standardize
- shape2mat
- sim_sar
- title: "Spatial autocorrelation"
- contents:
- aple
- expected_mc
- gr
- lg
- lisa
- mc
- me_diag
- moran_plot
- n_eff
- sp_diag
- row_standardize
- title: "Models"
desc: "Model fitting functions and methods"
- sp_diag
- title: "Spatial models"
- contents:
- starts_with("prep_")
- starts_with("stan_")
- title: "Methods and diagnostics for spatial models"
- contents:
- matches("geostan_fit")
- me_diag
- spatial
- posterior_predict
- priors
- title: "Convenience functions"
desc: Tools for working with spatial data and **geostan** models
- waic
- title: "Miscellaneous"
- contents:
- auto_gaussian
- edges
- eigen_grid
- get_shp
- make_EV
- prep_car_data
- prep_car_data2
- prep_icar_data
- prep_me_data
- prep_sar_data
- prep_sar_data2
- eigen_grid
- se_log
- shape2mat
- sim_sar
- student_t
- waic
- title: "Data"
- contents:
- georgia
Expand Down
2 changes: 1 addition & 1 deletion docs/404.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/LICENSE-text.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/LICENSE.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/articles/custom-spatial-models.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions docs/articles/index.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f57cc0f

Please sign in to comment.