Data Science Team Training 2022 (Class 2)

Hub for learners to connect, find calendar events, & documents related to CSTE's DSTT program.

Preferred methods for Geocoding addresses?

Hi all!
Jeremy from Michigan DHHS! Just putting out some feelers- 
I'm hoping to put together a map of providers in Tableau using a list given to me with all their addresses. Currently, I don't believe Tableau supports mapping using only addresses, so I've been looking into ways to obtain geocodes for these locations. Here's what I've been looking into so far:
  • Google Maps API
  • Python with other libraries
  • R / OpenStreetMap and nominatim
The first two options seem like they may not work for us, with cost and not being allowed to install python on our computers being prohibitive factors, so I'm currently exploring the third option today! I got started with trying it out late yesterday afternoon and got a couple of packages installed but plan on looking into it more extensively today. Out of curiosity, has anyone ever had this need? If so, what solutions are you using? Did you run into similar barriers like cost or IT imposed restrictions and were you able to either get through those barriers or circumvent them? 

I've only just gotten started on this yesterday, but still hoping to hear if any of you have any experiences or advice to share! Happy to report back if my efforts are fruitful, if anyone's interested.

Comments & Events

Miranda Smith, Epidemiologist/Data Visualization Coordinator
Hey Jeremy!

You are correct, Tableau does not allow you to visualize street address info. That said, if you convert those into Lat-Log points (2 columns), Tableau can accurately populate them on a map. 

I've previously used ArcGIS to geocode street address data. We have concurrent licenses in my department which is a potentially cost-saving route ya'll may be able to take. :)
Maria Moskwa
Hello Jeremy,

I have used ArcGIS and SAS to geocode address data for years. Previously I had used SAS to clean the data into variables for each address segments (street, city, state, zip code) as well as a single variable with all address information and geocoded in ArcGIS. 

I also downloaded the maps and look up tables from SAS's online website and geocoded entirely within SAS. SAS then produced a dataset with the latitude and longitude in decimal degrees I can't remember the projection it uses but be mindful of that, the standard project used is NAD 1983 I believe. 

While I have not done this in R or python I imagine similar resources are available and the process would be similar to SAS. Especially since R and Python are free. Also you can run SAS scripts in python, and I think R, so you can definitely utilize the maps and look up table resources online.

Good luck with your project!
~Maria
Jason Geslois, Advanced Epidemiologist
Hi Jeremy, I've done geocoding in R before and there's several ways and several packages it can be done with.  There's an R package called tidygeocoder that will connect to several different api's for selection of the data. There's also several examples online using ggmap package with Google's api. The OpenStreetMap api is a good one to use, and there are others like HERE and OpenCage api's also besides the big name ones (Esri, Bing, etc) but some may have limits etc like 2500 at a time. Another way is that if you are aren't comfortable with the coding aspects, QGIS software is a free and open source gis software comparable to ArcGIS that has several geocoding packages in it that are available with more point/click interface. I have used that for more stand alone one-off type projects when needed to geocode points, and may be the easiest approach, outside of the ArcGIS approach that Miranda mentioned, but if you need reproducibility and something that will be continual used over time with new points continually coming in, then R is probably the best approach for that. Hope this helps. 

tidygeocoder package help description
https://cran.r-project.org/web/packages/tidygeocoder/tidygeocoder.pdf 

example 
https://engineerpaige.com/geocoding-in-r/
June Bancroft, Senior Epidemiologist
Hi Jeremy,

We use our state supported geocoder, you might want to see if your state already has this in place. We have a Geospatial Enterprise Office in a sister agency in Oregon and they support the geocoder which uses an API REST service.

We also have an enterprise GIS license with ESRI but geocoding using their dataset cost credits. We also could not use Google as we are a state agency (and that is prohibited on their end)

June
Barb Tisi
Hi Jeremy,

You can try zip codes as well since addresses won’t work.

Barb
Patric Prado
Hello all,

I am happy to share an r pipeline I developed which interacts with arcgis for geocoding. It uses reticulate to use arcgis own native python platform to control geocoding and mapping x,y coordinates.

Thanks,

Patric
Remy Poudel
That would be an awesome, Patric.
Please share it with us.

Remy
Jeremy Kuo
Thank you all so much for the suggestions and advice! While ArcGIS might've been a possibility, previous attempts at obtaining licenses have not necessarily gone over very fruitfully, so I was hesitant to try and go down that rabbit hole again...

After doing some exploring, Jason Geslois, Advanced Epidemiologist Jason 's suggestion tidygeocoder suggestion ended up working very well for me! I only wish I had started with trying that out haha. Thanks again everyone, but totally down to hear what other folks do if there are more methods out there! Hope your projects are all going well!
Patric Prado
This is an example of a markdown file that you can use to access python and also run python code from R studio. Please let me know if you want to run through this. 

```{r COVID Geocoding}
 
library(reticulate)   # Bridging R and Python
library(dplyr)        # Data wrangling
library(sf)           # Working with spatial objects
 
save_shp <- paste0("D:\\COVID\\Output\\Geocode_vac_geocode.shp")
 
save_vax <- paste0("Geocode_vaxx.csv")
 
use_python("C:/Program Files/ArcGIS/Pro/bin/Python/envs/arcgispro-py3/python.exe", required = TRUE)
arcpy <- import("arcpy")
 
arcpy$env$overwriteOutput =TRUE
 
arcpy$GeocodeAddresses_geocoding(
  in_table = save_vax,
  address_locator = "//phs110.acphd.ph.local/DEPT/Cape\\GIS\\Composite.loc",
  in_address_fields = "'Street or Intersection' Address VISIBLE NONE;'City or Placename' RECIP_ADDRESS_CITY VISIBLE NONE;State RECIP_ADDRESS_STATE VISIBLE NONE;'ZIP Code' RECIP_ADDRESS_ZIP VISIBLE NONE",
  out_feature_class = save_shp)
 
save_folder <- paste0("D:\\COVID\\Output\\")
#X:\nCoV2020\Data\COVID-19_Analyses\R Scripts\Covid VM
 
```
 
```{python}
import arcpy, sys, string, os, traceback, re, time #, datetime
from arcpy import env
 
for attempt_no in range(5):
  try:
    arcpy.env.overwriteOutput = True
    inpoints = r.save_shp
    outfolder = r.save_folder
    outname = "VaxJoins"
    outpath = outfolder + os.sep
    temp01 = r"in_memory" + \\temp01
    temp02 = r"in_memory" + \\temp02
    temp03 = r"in_memory" + \\temp03
    arcpy.AddXY_management(inpoints)
    arcpy.CalculateField_management(inpoints, "X", '!POINT_X!', "PYTHON_9.3")
    arcpy.CalculateField_management(inpoints, "Y", '!POINT_Y!', "PYTHON_9.3")
    arcpy.SpatialJoin_analysis (inpoints, r"D:\\COVID\\Geocoding\\Places incl water.shp", temp01)
    arcpy.AddMessage("Places")
    arcpy.SpatialJoin_analysis (temp01, r"D:\\COVID\\Geocoding\\CT10 incl water.shp", temp02)
    arcpy.AddMessage("CT10")
    arcpy.SpatialJoin_analysis (temp02, r"D:\\COVID\\Geocoding\\AC vs US.shp", temp03)
    arcpy.AddMessage("County")
  except ValueError as error:
    if attempt_no < (num_retries - 1):
      print("Error: Retrying")
    else:
      raise error
 
with arcpy.da.UpdateCursor(temp03,["Postal","Match_addr"]) as cursor:
  for row in cursor:
    if (row[0] == ' ' and row[1] != ' '):
      row[0] = row[1][-5:]
    cursor.updateRow(row)

with arcpy.da.UpdateCursor(temp03,["Postal","Match_addr"]) as cursor:
  for row in cursor:
    if (row[0][-5:-4] == '-'):
      arcpy.AddMessage(row[0][-5:-4])
      row[0] = row[1][-10:-5]
      arcpy.AddMessage(row[1][-10:-5])
    cursor.updateRow(row)
 
arcpy.AlterField_management(temp03, 'USER_RECIP', 'RECIP_ID')
arcpy.AlterField_management(temp03, 'USER_REC_1', 'ADDRESS1')
arcpy.AlterField_management(temp03, 'USER_REC_2', 'ADDRESS2')
arcpy.AlterField_management(temp03, 'USER_REC_3', 'County_geo')
arcpy.AlterField_management(temp03, 'USER_REC_4', 'zipcode')
arcpy.AlterField_management(temp03, 'USER_REC_5', 'state_geo')
arcpy.AlterField_management(temp03, 'USER_ADDRE', 'geo_address')
arcpy.AlterField_management(temp03, 'IN_Street', 'Address')
arcpy.AlterField_management(temp03, 'USER_full_', 'full_address')
 
fieldNeedList = ["Match_addr",  "POINT_X", "POINT_Y", "NAME", "Place", "CT10", "Postal", "RECIP_ID", "ADDRESS1", "ADDRESS2", "County_geo", "zipcode", "state_geo", "geo_address","Address","full_address"]
 
 
fieldNameList = []
fieldObjList = arcpy.ListFields(temp03)
for field in fieldObjList:
  if not field.required:
    if not field.name in fieldNeedList:
      fieldNameList.append(field.name)
        
arcpy.DeleteField_management(temp03, fieldNameList)
arcpy.AlterField_management(temp03, 'POINT_X', 'X')
arcpy.AlterField_management(temp03, 'POINT_Y', 'Y')
arcpy.AlterField_management(temp03, 'NAME', 'County')
arcpy.AlterField_management(temp03, 'Postal', 'Zip')
arcpy.CopyFeatures_management(temp03, outpath + outname + ".shp")
arcpy.Delete_management("in_memory") 
 
```