Skip to content

Commit 79244c9

Browse files
committed
Vectorize zip_distance() function
1 parent 60bc3c9 commit 79244c9

6 files changed

Lines changed: 87 additions & 19 deletions

File tree

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: zipcodeR
22
Title: Data & Functions for Working with US ZIP Codes
3-
Version: 0.3.2
3+
Version: 0.3.3
44
Authors@R:
55
person(given = "Gavin",
66
family = "Rozzi",
@@ -16,7 +16,7 @@ BugReports: https://github.com/gavinrozzi/zipcodeR/issues/
1616
Encoding: UTF-8
1717
LazyData: true
1818
Roxygen: list(markdown = TRUE)
19-
RoxygenNote: 7.1.1
19+
RoxygenNote: 7.1.2
2020
Imports:
2121
rlang,
2222
stringr,

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# *News*
22

3+
# zipcodeR 0.3.3
4+
- This update vectorizes the `zip_distance()` function to allow distance calculations between two vectors or columns of ZIP codes. The function now returns a data.frame of the resulting distance calculation.
5+
- `zip_distance()` now includes an additional argument, units, which allows selection between miles and meters for distance calculations.
6+
37
# zipcodeR 0.3.2
48
- `zip_code_db` has been updated.
59
- `download_zip_data()` has been refactored to make data updates more easily accessible and compare against existing data. Data is now directly downloaded from the upstream source and the existing data GitHub repository will no longer be updated.

R/download_data.r

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ download_zip_data <- function(force = FALSE) {
2424
if (file.exists(system.file("data", "zcta_crosswalk.rda", package = "zipcodeR")) == TRUE && force == FALSE) {
2525
cat("Crosswalk file found, skipping")
2626
} else if (file.exists(system.file("data", "zcta_crosswalk.rda", package = "zipcodeR")) == FALSE) {
27-
cat(paste("zipcodeR: Downloading ZCTA crosswalk file","\n"))
27+
cat(paste("zipcodeR: Downloading ZCTA crosswalk file", "\n"))
2828
utils::download.file(url_crosswalk, paste0(system.file("data", package = "zipcodeR"), "/zcta_crosswalk.rda"))
2929
} else if (force == TRUE) {
30-
cat(paste("zipcodeR: forcing Download of ZCTA crosswalk file","\n"))
30+
cat(paste("zipcodeR: forcing Download of ZCTA crosswalk file", "\n"))
3131
utils::download.file(url_crosswalk, paste0(system.file("data", package = "zipcodeR"), "/zcta_crosswalk.rda"))
3232
}
3333

R/zip_helper_functions.R

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,31 +65,72 @@ normalize_zip <- function(zipcode) {
6565
#' Calculate the distance between two ZIP codes in miles
6666
#'
6767
#'
68-
#' @param zipcode_a First ZIP code
69-
#' @param zipcode_b Second ZIP code
68+
#' @param zipcode_a First vector of ZIP codes
69+
#' @param zipcode_b Second vector of ZIP codes
7070
#' @param lonlat lonlat argument to pass to raster::pointDistance() to select method of distance calculation. Default is TRUE to calculate distance over a spherical projection. FALSE will calculate the distance in Euclidean (planar) space.
71-
#' @return distance calculated from centroids of each ZIP code in miles
71+
#' @param units Specify which units to return distance calculations in. Choices include meters or miles.
72+
#' @return a data.frame containing a column for each ZIP code and a new column containing the distance between the two columns of ZIP code
7273
#'
7374
#' @examples
75+
#' Example with a single pair of ZIP codes
7476
#' zip_distance("08731", "08901")
77+
#'
78+
#' zip_codes <- tribble(~zip_a, ~zip_b,
79+
#' "08731", "08901",
80+
#' "08734", "08005")
81+
#'
82+
#' Example with two vectors of ZIP codes
83+
#' zip_distance(zip_codes$zip_a,zip_codes$zip_b)
84+
#'
7585
#' @importFrom raster pointDistance
7686
#' @export
77-
zip_distance <- function(zipcode_a, zipcode_b, lonlat = TRUE) {
87+
zip_distance <- function(zipcode_a, zipcode_b, lonlat = TRUE, units = "miles") {
88+
zipcode_a <- as.character(zipcode_a)
89+
zipcode_b <- as.character(zipcode_b)
7890

7991
# Create an instance of the ZIP code database for calculating distance,
8092
# filter to those with lat / lon pairs
8193
zip_data <- zip_code_db %>%
8294
dplyr::filter(.data$lat != "NA" & .data$lng != "NA") %>%
83-
dplyr::filter(.data$zipcode == zipcode_a | .data$zipcode == zipcode_b) %>%
95+
dplyr::filter(.data$zipcode %in% zipcode_a | .data$zipcode %in% zipcode_b) %>%
8496
dplyr::select(.data$zipcode, .data$lat, .data$lng)
8597

86-
distance <- raster::pointDistance(c(zip_data$lng[1], zip_data$lat[1]), c(zip_data$lng[2], zip_data$lat[2]), lonlat = lonlat)
98+
# Filter the data points for each set of ZIP codes
99+
zip_a_data <- zip_data %>%
100+
dplyr::filter(.data$zipcode %in% zipcode_a)
101+
102+
zip_b_data <- zip_data %>%
103+
dplyr::filter(.data$zipcode %in% zipcode_b)
104+
105+
# Create a matrix of points to feed to raster
106+
points_a <- cbind(cbind(zip_a_data$lng, zip_a_data$lat))
107+
points_b <- cbind(cbind(zip_b_data$lng, zip_b_data$lat))
108+
109+
# Calculate the distance matrix between both sets of points
110+
distance <- raster::pointDistance(points_a, points_b, lonlat = lonlat)
87111

88-
# Convert meters to miles for distance measurement
89-
distance <- distance * 0.000621371
112+
# Convert the distance matrix from meters to miles
113+
if (units == "miles") {
114+
distance <- distance * 0.000621371
115+
}
90116

91117
# Round to 2 decimal places to match search_radius()
92118
distance <- round(distance, digits = 2)
93119

94-
return(distance)
120+
# Put together the results in a data.frame
121+
result <- data.frame(zipcode_a, zipcode_b, distance)
122+
123+
# Insert NA values in rows that could not be found in zip_code_db
124+
for (i in 1:nrow(result)) {
125+
if (result$zipcode_a[i] %in% zip_data$zipcode == FALSE) {
126+
result$distance[i] <- NA
127+
}
128+
129+
if (result$zipcode_b[i] %in% zip_data$zipcode == FALSE) {
130+
result$distance[i] <- NA
131+
}
132+
}
133+
134+
135+
return(result)
95136
}

codemeta.json

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
],
1515
"issueTracker": "https://github.com/gavinrozzi/zipcodeR/issues/",
1616
"license": "https://spdx.org/licenses/GPL-3.0",
17-
"version": "0.3.2",
17+
"version": "0.3.3",
1818
"programmingLanguage": {
1919
"@type": "ComputerLanguage",
2020
"name": "R",
@@ -220,6 +220,18 @@
220220
},
221221
"sameAs": "https://CRAN.R-project.org/package=httr"
222222
},
223+
{
224+
"@type": "SoftwareApplication",
225+
"identifier": "curl",
226+
"name": "curl",
227+
"provider": {
228+
"@id": "https://cran.r-project.org",
229+
"@type": "Organization",
230+
"name": "Comprehensive R Archive Network (CRAN)",
231+
"url": "https://cran.r-project.org"
232+
},
233+
"sameAs": "https://CRAN.R-project.org/package=curl"
234+
},
223235
{
224236
"@type": "SoftwareApplication",
225237
"identifier": "RSQLite",
@@ -253,7 +265,7 @@
253265
],
254266
"releaseNotes": "https://github.com/gavinrozzi/zipcodeR/blob/master/NEWS.md",
255267
"readme": "https://github.com/gavinrozzi/zipcodeR/blob/master/README.md",
256-
"fileSize": "3064.175KB",
268+
"fileSize": "3771.828KB",
257269
"contIntegration": ["https://github.com/gavinrozzi/zipcodeR/actions", "https://codecov.io/gh/gavinrozzi/zipcodeR"],
258270
"citation": [
259271
{

man/zip_distance.Rd

Lines changed: 15 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)