How do I find other zipcodes that touch a particular zipcode?

r, zipcode

Solution

If you have access to a shapefile, this is relatively straightforward with the help of the `spdep` package.

Here's a standalone example using Californian zip code data (~3.5MB download):

# load libraries
library(rgdal)
library(spdep)

# download, unzip and import shapefile
download.file('http://geocommons.com/overlays/305142.zip', {f<-tempfile()})
unzip(f, exdir=tempdir())
shp <- readOGR(tempdir(), 'tigerline_shapefile_2010_2010_state_california_2010_census_5-digit_zip_code_tabulation_area_zcta5_state-based')

# identify neighbours for each poly
nbs <- setNames(poly2nb(shp), shp$ZCTA5CE10)

# convert to a binary neighbour matrix
nbs.mat <- nb2mat(nbs, zero.policy=TRUE, style='B')

# see?rgeos::gTouches for an alternative to the above steps

# assign zip codes as dimension names
dimnames(nbs.mat) <- list(shp$ZCTA5CE10, shp$ZCTA5CE10)

For our dataset, this returns a 1769 x 1769 matrix indicating which zip codes are neighbours. The first 10 rows and 10 columns look like this:

nbs.mat[1:10, 1:10]

##       94601 94501 94560 94587 94580 94514 94703 95601 95669 95901
## 94601     0     1     0     0     0     0     0     0     0     0
## 94501     1     0     0     0     0     0     0     0     0     0
## 94560     0     0     0     0     0     0     0     0     0     0
## 94587     0     0     0     0     0     0     0     0     0     0
## 94580     0     0     0     0     0     0     0     0     0     0
## 94514     0     0     0     0     0     0     0     0     0     0
## 94703     0     0     0     0     0     0     0     0     0     0
## 95601     0     0     0     0     0     0     0     0     0     0
## 95669     0     0     0     0     0     0     0     0     0     0
## 95901     0     0     0     0     0     0     0     0     0     0

Optionally, if you want a two-column matrix giving neighbouring pairs of zip codes (i.e., zip code in col 1, and neighbouring zip code in col 2), you can use the following.

nbs.list <- sapply(row.names(nbs.mat), function(x) names(which(nbs.mat[x, ] == 1)))

nbs.pairs <- data.frame(zipcode=rep(names(nbs.list), sapply(nbs.list, length)), 
                        neighbour=unlist(nbs.list))

head(nbs.pairs)

##        zipcode neighbour
## 946011   94601     94501
## 946012   94601     94602
## 946013   94601     94605
## 946014   94601     94606
## 946015   94601     94621
## 946016   94601     94619    

Problem

I want to create a matrix for around 200 zipcodes and neighboring zipcodes that touch those zipcodes. The matrix would be 200*200 with 1's for the cells in which the two zipcodes touch and 0 when they are not neighboring zipcodes. How could I create or get such a matrix? Thank you very much. Best,

Original source