# Doing nearest neighbors accounting for road distance in R

I was wondering if it was possible to do nearest neighbor analysis using road distance in R? I've seen some attempts to do it with QGIS (Calculating the nearest neighbour using given road network in QGIS), but don't know if an R functionality is available.

For example, if I am looking at nursing homes nationwide and trying to identify the five closest hospitals to each one. I had used Euclidean distance before using st_nn but I am now interested in trying to replicate the analysis using road distance. I know that if I had any two points I could use a number of packages to define road distance between them (e.g. googleway), but not sure if that is available for k-nearest neighbor approaches.

I would probably use `dodgr` alongside `sf` for that. As an meta-example, consider a road network from OSM labelled `"osm_file"`, where we filter the most important roads:

``````roads <- read_sf("osm_file") %>%
st_transform(crs = "WGS84") %>%
mutate(id = row_number())
``````

We can now create street networks with `dodgr`, and in this example select the largest enclosed network:

``````# Create road network graph
graph <- weight_streetnet(roads, wt_profile = "motorcar", type_col = "fclass")
graph_simple <- graph [graph\$component == 1, ]
vertices <- dodgr_vertices(graph_simple)
``````

It is important to investigate how many components are in the graph. Then, we define coordinates of your from and to points. In this case, `home` and `hospital` would be `sf` POINTS objects:

``````# Define from coordinates
from_x <- st_coordinates(home)[,"X"]
from_y <- st_coordinates(home)[,"Y"]

# Define to coordinates
to_x <- st_coordinates(hospital)[,"X"]
to_y <- st_coordinates(hospital)[,"Y"]
``````

And then finally calculate the distances along the road network:

``````distances <- dodgr_dists (graph = graph_simple,
from = cbind (from_x, from_y),
to = cbind (to_x, to_y))
``````

Then you can filter the distances and find the five closest hospitals for each home. It is important to note that you can get really long distances if your selected component does not provide good coverage of your input points. Alternatively, you could loop over each input point and only select the roads which are within a certain buffer (let's say you are not interested in hospitals more than 100 km away for example). You do not have to worry about your from/to points not being on the roads themselves, since `dodgr` is smart:

For spatial graphs—that is, those containing columns of latitudes and longitudes (or “x” and “y”)—routing points can be represented by a simple matrix of arbitrary latitudes and longitudes (or, again, “x” and “y”). dodgr_distances() will map these points to the closest network points, and return corresponding shortest-path distances.

In addition, you can run the calculations in parallel, making it extremely fast. I suggest you have a look at some examples on their page.

If would be good if you clarified, distance along the network (roads) or across the entire spatial domain in relation to the network? There are some network tools available in one of the spatstat packages spatstat.linnet (on CRAN). Not knowing your data I can only speculate but, spatstat.linnet::distfun.lpp may be what your are after. This function supports distance analysis of a point pattern (events) along a network. For calculating distance or nearest neighbors between two different point patterns (ie., nursing homes and hospitals) you can use the bivariate version `spatstat.linnet::crossdist` to return a distance matrix or `spatstat.linnet::nndist` for k nearest neighbors. I believe that there is a method available for lpp class objects with the `nndist` function but if not, you will have to query the distance matrix, returned from `crossdist`, for the desired knn.

• I'm not certain I completely comprehend the distinction being made, so I clarified my original post a bit. Thanks. Feb 6, 2023 at 21:31
• The `distfun` function, with the k=5 argument, I indicated would work for your nursing home question. You "network" would be roads with nursing homes and hospitals the "events". You will have to read up on the package to understand how to structure your data. For your point pattern, you will have to structure it as a marked (hospitals, nursing homes) ppp object. There are very good vignettes associated with each spatstat library. Feb 6, 2023 at 21:37