| Title: | Geospatial Distribution Dynamics for Simple Features |
|---|---|
| Description: | Tools for exploratory geospatial distribution dynamics with 'sf' objects and tidy data. Provides pooled and time-specific classification of longitudinal spatial values, classic discrete Markov transition matrices, spatial Markov matrices conditioned on spatial-lag classes, endpoint and adjacent rank mobility summaries, ergodic-chain summaries, transition-regime homogeneity tests, and 'ggplot2' visualizations. Methods follow Rey (2001) <doi:10.1111/j.1538-4632.2001.tb00444.x> and Rey et al. (2016) <doi:10.1007/s10109-016-0234-x>; design is inspired by the Python 'PySAL' 'giddy' package <https://pysal.org/giddy/>. |
| Authors: | Dmitry Shkolnik [aut, cre] |
| Maintainer: | Dmitry Shkolnik <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.2.0 |
| Built: | 2026-10-01 07:45:42 UTC |
| Source: | https://github.com/dshkol/griddy |
Class Intervals Used By A griddy Object
class_intervals(x, ...)class_intervals(x, ...)
x |
A griddy result object. |
... |
Reserved for future methods. |
A tibble of class intervals when available.
panel <- data.frame(id = rep(1:3, each = 2), year = rep(2020:2021, 3), value = 1:6) classes <- classify_dynamics(panel, id, year, value, k = 3) class_intervals(classes)panel <- data.frame(id = rep(1:3, each = 2), year = rep(2020:2021, 3), value = 1:6) classes <- classify_dynamics(panel, id, year, value, k = 3) class_intervals(classes)
Converts numeric values in a long panel into ordered classes suitable for transition analysis.
classify_dynamics( data, id, time, value, method = c("pooled_quantile", "time_quantile", "fixed", "existing"), k = 5, breaks = NULL, labels = NULL )classify_dynamics( data, id, time, value, method = c("pooled_quantile", "time_quantile", "fixed", "existing"), k = 5, breaks = NULL, labels = NULL )
data |
A data frame or |
id, time, value
|
Columns identifying spatial unit, time, and value. |
method |
Classification method. |
k |
Number of quantile classes. |
breaks |
Breaks for |
labels |
Optional class labels. |
A data frame or sf object with a class column and class
grd_classes.
panel <- data.frame( id = rep(letters[1:4], each = 3), year = rep(2020:2022, times = 4), value = c(8, 9, 11, 10, 12, 13, 15, 14, 16, 20, 22, 25) ) classes <- classify_dynamics(panel, id, year, value, k = 3) classes class_intervals(classes)panel <- data.frame( id = rep(letters[1:4], each = 3), year = rep(2020:2022, times = 4), value = c(8, 9, 11, 10, 12, 13, 15, 14, 16, 20, 22, 25) ) classes <- classify_dynamics(panel, id, year, value, k = 3) classes class_intervals(classes)
Computes the matrix of mean first-passage times for an ergodic transition
probability matrix following Kemeny and Snell: entry [i, j] is the
expected number of transitions to reach class j for the first time
starting from class i. Diagonal entries are mean recurrence times,
the reciprocal of the stationary distribution.
first_passage(x)first_passage(x)
x |
A |
A square numeric matrix of mean first-passage times.
prob <- matrix(c(0.9, 0.1, 0.2, 0.8), nrow = 2, byrow = TRUE) first_passage(prob)prob <- matrix(c(0.9, 0.1, 0.2, 0.8), nrow = 2, byrow = TRUE) first_passage(prob)
Tests whether transition dynamics are homogeneous across regimes – for a
spatial Markov object, whether the transition matrices conditioned on
spatial-lag class genuinely differ from the pooled matrix (Rey, Kang, and
Wolf 2016). Three statistics are reported: a Pearson chi-squared Q test and
a likelihood-ratio test with the degrees-of-freedom adjustment of
Bickenbach and Bald (2003), and the Kullback information test (Kullback,
Kupperman, and Ku 1962). The Pearson and likelihood-ratio statistics mirror
the PySAL giddy Spatial_Markov homogeneity attributes. The Kullback
statistic uses origin-state (row) margins; this deliberately differs from
giddy.markov.kullback() through giddy 2.3.9, which uses terminal-state
(column) margins for the stratum-specific term.
homogeneity_test(x, ...)homogeneity_test(x, ...)
x |
A |
... |
Reserved for future methods. |
A tibble with one row per test (chi2, likelihood_ratio,
kullback) and columns test, statistic, df, and p_value. The
null hypothesis is that all regimes share the pooled transition matrix;
small p-values indicate the conditional dynamics differ.
panel <- data.frame( id = rep(1:9, each = 3), year = rep(2020:2022, times = 9), value = c( 1, 2, 3, 4, 3, 5, 6, 7, 6, 8, 9, 10, 11, 10, 12, 13, 14, 13, 15, 16, 17, 18, 17, 19, 20, 21, 20 ) ) grid <- sf::st_sf( id = 1:9, geometry = sf::st_make_grid( sf::st_bbox(c(xmin = 0, ymin = 0, xmax = 3, ymax = 3)), n = c(3, 3) ) ) |> dplyr::mutate( nb = sfdep::st_contiguity(geometry), wt = sfdep::st_weights(nb) ) spatial <- spatial_markov(panel, id, year, value, geometry = grid, k = 3) homogeneity_test(spatial)panel <- data.frame( id = rep(1:9, each = 3), year = rep(2020:2022, times = 9), value = c( 1, 2, 3, 4, 3, 5, 6, 7, 6, 8, 9, 10, 11, 10, 12, 13, 14, 13, 15, 16, 17, 18, 17, 19, 20, 21, 20 ) ) grid <- sf::st_sf( id = 1:9, geometry = sf::st_make_grid( sf::st_bbox(c(xmin = 0, ymin = 0, xmax = 3, ymax = 3)), n = c(3, 3) ) ) |> dplyr::mutate( nb = sfdep::st_contiguity(geometry), wt = sfdep::st_weights(nb) ) spatial <- spatial_markov(panel, id, year, value, geometry = grid, k = 3) homogeneity_test(spatial)
Spatial Lag Intervals Used By A Spatial Markov Object
lag_intervals(x)lag_intervals(x)
x |
A |
A tibble of spatial-lag class intervals.
panel <- data.frame( id = rep(1:4, each = 2), year = rep(2020:2021, times = 4), value = c(1, 2, 2, 3, 4, 3, 5, 6) ) grid <- sf::st_sf( id = 1:4, geometry = sf::st_make_grid( sf::st_bbox(c(xmin = 0, ymin = 0, xmax = 2, ymax = 2)), n = c(2, 2) ) ) |> dplyr::mutate( nb = sfdep::st_contiguity(geometry), wt = sfdep::st_weights(nb) ) spatial <- spatial_markov(panel, id, year, value, geometry = grid, k = 2) lag_intervals(spatial)panel <- data.frame( id = rep(1:4, each = 2), year = rep(2020:2021, times = 4), value = c(1, 2, 2, 3, 4, 3, 5, 6) ) grid <- sf::st_sf( id = 1:4, geometry = sf::st_make_grid( sf::st_bbox(c(xmin = 0, ymin = 0, xmax = 2, ymax = 2)), n = c(2, 2) ) ) |> dplyr::mutate( nb = sfdep::st_contiguity(geometry), wt = sfdep::st_weights(nb) ) spatial <- spatial_markov(panel, id, year, value, geometry = grid, k = 2) lag_intervals(spatial)
Estimates transition counts and probabilities between adjacent periods for a classified long panel.
markov_dynamics(classes, id, time, state = class)markov_dynamics(classes, id, time, state = class)
classes |
A classified data frame from |
id, time, state
|
Columns identifying spatial unit, time, and state. |
A grd_markov object.
panel <- data.frame( id = rep(letters[1:4], each = 3), year = rep(2020:2022, times = 4), value = c(8, 9, 11, 10, 12, 13, 15, 14, 16, 20, 22, 25) ) classes <- classify_dynamics(panel, id, year, value, k = 3) markov <- markov_dynamics(classes, id, year, class) markov transition_matrix(markov) steady_state(markov)panel <- data.frame( id = rep(letters[1:4], each = 3), year = rep(2020:2022, times = 4), value = c(8, 9, 11, 10, 12, 13, 15, 14, 16, 20, 22, 25) ) classes <- classify_dynamics(panel, id, year, value, k = 3) markov <- markov_dynamics(classes, id, year, class) markov transition_matrix(markov) steady_state(markov)
Computes scalar mobility indices summarising how much movement a transition
probability matrix implies, following Formby, Smith, and Zheng (2004) and
mirroring giddy.mobility.markov_mobility() in PySAL giddy.
mobility_index( x, measure = c("prais", "determinant", "eigen", "bartholomew1", "bartholomew2"), initial = NULL )mobility_index( x, measure = c("prais", "determinant", "eigen", "bartholomew1", "bartholomew2"), initial = NULL )
x |
A |
measure |
Character vector of indices to compute. Any of:
|
initial |
Optional initial distribution over classes used by the
Bartholomew indices. Defaults to the uniform distribution, matching
|
A named numeric vector with one element per requested measure. All indices are 0 for the identity matrix (no mobility) and increase with mobility.
prob <- matrix(c(0.9, 0.1, 0.2, 0.8), nrow = 2, byrow = TRUE) mobility_index(prob) mobility_index(prob, measure = "prais")prob <- matrix(c(0.9, 0.1, 0.2, 0.8), nrow = 2, byrow = TRUE) mobility_index(prob) mobility_index(prob, measure = "prais")
Plot Rank Mobility
plot_rank_mobility(x)plot_rank_mobility(x)
x |
A |
A ggplot object.
Plot Spatial Markov Matrices
plot_spatial_markov(x)plot_spatial_markov(x)
x |
A |
A ggplot object.
panel <- data.frame( id = rep(1:4, each = 2), year = rep(2020:2021, times = 4), value = c(1, 2, 2, 3, 4, 3, 5, 6) ) grid <- sf::st_sf( id = 1:4, geometry = sf::st_make_grid( sf::st_bbox(c(xmin = 0, ymin = 0, xmax = 2, ymax = 2)), n = c(2, 2) ) ) |> dplyr::mutate( nb = sfdep::st_contiguity(geometry), wt = sfdep::st_weights(nb) ) spatial <- spatial_markov(panel, id, year, value, geometry = grid, k = 2) plot_spatial_markov(spatial)panel <- data.frame( id = rep(1:4, each = 2), year = rep(2020:2021, times = 4), value = c(1, 2, 2, 3, 4, 3, 5, 6) ) grid <- sf::st_sf( id = 1:4, geometry = sf::st_make_grid( sf::st_bbox(c(xmin = 0, ymin = 0, xmax = 2, ymax = 2)), n = c(2, 2) ) ) |> dplyr::mutate( nb = sfdep::st_contiguity(geometry), wt = sfdep::st_weights(nb) ) spatial <- spatial_markov(panel, id, year, value, geometry = grid, k = 2) plot_spatial_markov(spatial)
Plot A Transition Matrix
plot_transition_matrix(x)plot_transition_matrix(x)
x |
A |
A ggplot object.
panel <- data.frame(id = rep(1:4, each = 2), year = rep(2020:2021, 4), value = 1:8) markov <- panel |> classify_dynamics(id, year, value, k = 2) |> markov_dynamics(id, year, class) plot_transition_matrix(markov)panel <- data.frame(id = rep(1:4, each = 2), year = rep(2020:2021, 4), value = 1:8) markov <- panel |> classify_dynamics(id, year, value, k = 2) |> markov_dynamics(id, year, class) plot_transition_matrix(markov)
Computes simple rank changes for map-ready exploratory analysis.
rank_mobility( data, id, time, value, compare = c("endpoint", "adjacent"), descending = TRUE )rank_mobility( data, id, time, value, compare = c("endpoint", "adjacent"), descending = TRUE )
data |
A long data frame or |
id, time, value
|
Columns identifying spatial unit, time, and value. |
compare |
|
descending |
If |
A grd_rank_mobility data frame or sf object.
panel <- data.frame( id = rep(letters[1:4], each = 3), year = rep(2020:2022, times = 4), value = c(8, 9, 11, 10, 12, 13, 15, 14, 16, 20, 22, 25) ) rank_mobility(panel, id, year, value)panel <- data.frame( id = rep(letters[1:4], each = 3), year = rep(2020:2022, times = 4), value = c(8, 9, 11, 10, 12, 13, 15, 14, 16, 20, 22, 25) ) rank_mobility(panel, id, year, value)
Computes the expected number of consecutive periods a unit remains in each
class once it enters it, 1 / (1 - p_ii). Absorbing classes (p_ii = 1)
have infinite sojourn times.
sojourn_time(x)sojourn_time(x)
x |
A |
A named numeric vector of expected sojourn times, one per class.
prob <- matrix(c(0.9, 0.1, 0.2, 0.8), nrow = 2, byrow = TRUE) sojourn_time(prob)prob <- matrix(c(0.9, 0.1, 0.2, 0.8), nrow = 2, byrow = TRUE) sojourn_time(prob)
Estimates transition matrices conditioned on the class of each unit's spatial lag at the start of the transition period.
spatial_markov( data, id, time, value, geometry = NULL, listw = NULL, nb = NULL, k = 5, lag_k = k, class_method = c("pooled_quantile", "time_quantile", "fixed"), zero.policy = TRUE )spatial_markov( data, id, time, value, geometry = NULL, listw = NULL, nb = NULL, k = 5, lag_k = k, class_method = c("pooled_quantile", "time_quantile", "fixed"), zero.policy = TRUE )
data |
A long data frame or |
id, time, value
|
Columns identifying spatial unit, time, and value. |
geometry |
An |
listw |
A row-standardized |
nb |
A |
k |
Number of value classes. |
lag_k |
Number of spatial-lag classes. |
class_method |
Value classification method passed to |
zero.policy |
Passed to |
A grd_spatial_markov object.
panel <- data.frame( id = rep(1:4, each = 3), year = rep(2020:2022, times = 4), value = c(1, 2, 3, 2, 3, 4, 4, 3, 5, 5, 6, 7) ) grid <- sf::st_sf( id = 1:4, geometry = sf::st_make_grid( sf::st_bbox(c(xmin = 0, ymin = 0, xmax = 2, ymax = 2)), n = c(2, 2) ) ) |> dplyr::mutate( nb = sfdep::st_contiguity(geometry), wt = sfdep::st_weights(nb) ) spatial <- spatial_markov(panel, id, year, value, geometry = grid, k = 2) spatial lag_intervals(spatial) transition_matrix(spatial, "count", lag_class = "Q1")panel <- data.frame( id = rep(1:4, each = 3), year = rep(2020:2022, times = 4), value = c(1, 2, 3, 2, 3, 4, 4, 3, 5, 5, 6, 7) ) grid <- sf::st_sf( id = 1:4, geometry = sf::st_make_grid( sf::st_bbox(c(xmin = 0, ymin = 0, xmax = 2, ymax = 2)), n = c(2, 2) ) ) |> dplyr::mutate( nb = sfdep::st_contiguity(geometry), wt = sfdep::st_weights(nb) ) spatial <- spatial_markov(panel, id, year, value, geometry = grid, k = 2) spatial lag_intervals(spatial) transition_matrix(spatial, "count", lag_class = "Q1")
Estimate Stationary Distribution
steady_state(x)steady_state(x)
x |
A |
A numeric vector.
prob <- matrix(c(0.8, 0.2, 0.3, 0.7), nrow = 2, byrow = TRUE) steady_state(prob)prob <- matrix(c(0.8, 0.2, 0.3, 0.7), nrow = 2, byrow = TRUE) steady_state(prob)
Extract A Transition Matrix
transition_matrix(x, type = c("probability", "count"), lag_class = NULL)transition_matrix(x, type = c("probability", "count"), lag_class = NULL)
x |
A |
type |
|
lag_class |
Optional lag class for |
A matrix.
panel <- data.frame( id = rep(letters[1:4], each = 3), year = rep(2020:2022, times = 4), value = c(8, 9, 11, 10, 12, 13, 15, 14, 16, 20, 22, 25) ) markov <- panel |> classify_dynamics(id, year, value, k = 3) |> markov_dynamics(id, year, class) transition_matrix(markov, "count")panel <- data.frame( id = rep(letters[1:4], each = 3), year = rep(2020:2022, times = 4), value = c(8, 9, 11, 10, 12, 13, 15, 14, 16, 20, 22, 25) ) markov <- panel |> classify_dynamics(id, year, value, k = 3) |> markov_dynamics(id, year, class) transition_matrix(markov, "count")
Per-capita personal income for the 48 contiguous US states in nominal
dollars. Mirrors the canonical usjoin panel used in PySAL giddy and the
spatial Markov literature, so examples and validation in this package are
directly comparable to that reference work.
usjoinusjoin
A tibble with 3,888 rows (48 states x 81 years) and 4 columns:
State name.
State FIPS code, integer.
Year, integer 1929 to 2009.
Nominal per-capita personal income, integer USD.
PySAL libpysal examples/us_income/usjoin.csv. The original series
is constructed from US Bureau of Economic Analysis state personal income
tables. See https://github.com/pysal/libpysal.
Rey, S. J. (2001). Spatial empirics for economic growth and convergence. Geographical Analysis, 33(3), 195-214.
Rey, S. J., Kang, W., & Wolf, L. (2016). The properties of tests for spatial effects in discrete Markov chain models of regional income distribution dynamics. Journal of Geographical Systems, 18(4), 377-398.
data(usjoin) head(usjoin) range(usjoin$year)data(usjoin) head(usjoin) range(usjoin$year)