Skip to main content
3 of 3
added 86 characters in body

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 sane 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 or give the wrong matches becuase variant names can be very distinct. So in many cases you will end up doing some manual replacements like:

df[df$name=="Yerevan City", 'match'] <- "Erevan"

In both cases followed by

m <- merge(arm, df, by.x='NAME_1', by.y='match')

In any case you will want to check if sum(table(i) > 1) == 0; although merge should fail anyway if there are duplicate matches.