I want to add some details to Farid Cher's answer as this is a very common problem. Using amatch
can do wonders, but with these Spatial
objects you should not use base::merge
and not access the @data
slot. That would inevitably leads to a terrible mess (base::merge
changes the order of records, and they would no longer match geometries).
Instead, use the sp::merge
method, by using the SpatialPolygonsDataFrame
as first argument in merge
. Also note the potential problem of having duplicated records. And I added data so that the example is self-contained and reproducible.
library(raster)
#example data.frame
name <- c("Aragatsotn", "Ararat", "Armavir", "Gaghark'unik'", "Kotayk", "Lorri", "Shirak", "Syunik'", "Tavush", "Vayots' Dzor", "Yerevan City","Aragatsotn")
value <- runif(12, 0.0, 1.0)
df <- data.frame(name, value)
# example SpatialPolygonsDataFrame
arm <- getData('GADM', country='ARM', level=1)[, c('NAME_1')]
This
merge(arm, df, by.x='NAME_1', by.y='name')
fails with message
#Error in .local(x, y, ...) : non-unique matches detected
Because there are two records for "Aragatsotn" in df
. You could do
merge(arm, df, by.x='NAME_1', by.y='name', duplicateGeoms=TRUE)
But normally the same approach is to use someting like
df <- aggregate(df[, 'value', drop=FALSE], df[, 'name', drop=FALSE], mean)
m <- merge(arm, df, by.x='NAME_1', by.y='name')
data.frame(m)
data.frame(m)
# NAME_1 value
#1 Aragatsotn 0.421576186
#2 Ararat 0.003138734
#3 Armavir 0.703402672
#4 Erevan NA
#5 Gegharkunik NA
#6 Kotayk 0.926883799
#7 Lori NA
#8 Shirak 0.430585540
#9 Syunik NA
#10 Tavush 0.121784395
#11 Vayots Dzor NA
Now, merge does not work well in this case because the names do not match. So you can use
i <- amatch(df$name, arm$NAME_1, maxDist = 3)
df$match[!is.na(i)] <- arm$NAME_1[i[!is.na(i)]]
df
# name value match
#1 Aragatsotn 0.421576186 Aragatsotn
#2 Ararat 0.003138734 Ararat
#3 Armavir 0.703402672 Armavir
#4 Gaghark'unik' 0.682169824 Gegharkunik
#5 Kotayk 0.926883799 Kotayk
#6 Lorri 0.128894086 Lori
#7 Shirak 0.430585540 Shirak
#8 Syunik' 0.163562936 Syunik
#9 Tavush 0.121784395 Tavush
#10 Vayots' Dzor 0.383439033 Vayots Dzor
#11 Yerevan City 0.168033419 <NA>
Almost there, but "Yerevan City" did not match with "Erevan". In this case you can increase maxDist
i <- amatch(df$name, arm$NAME_1, maxDist = 10)
df$match[!is.na(i)] <- arm$NAME_1[i[!is.na(i)]]
But increasing maxDist
will not always work. Sometimes variant names are very different. So in many cases you will end up doing some manual replacements like:
df[df$name=="Yerevan City", 'match'] <- "Erevan"
In any case you will want to check if sum(table(i) > 1) == 0
; although merge
should fail anyway if there are duplicate matches.