Due to time constrain, I will only include SpatialPolygonsDataFrame here. More details about sp class can be found in Extra 2.
First, the diagram
Here, we will create Polygon class. For example, Sr1 has the vertices \((2,2)\), \((4,3)\), \((4,5)\) and \((1,4)\). Note that \((2,2)\) needs to be written twice, since it is both the starting vertex and the ending vertex.
library(sp)
#getClass("Polygon")
Sr1 = Polygon(cbind(c(2,4,4,1,2),c(2,3,5,4,2)))
Sr2 = Polygon(cbind(c(5,4,2,5),c(2,3,2,2)))
Sr3 = Polygon(cbind(c(4,4,5,10,4),c(5,3,2,5,5)))
Sr4 = Polygon(cbind(c(5,6,6,5,5),c(4,4,3,3,4)), hole = TRUE)
A Polygons can contain any number of Polygon (including only 1 Polygon).
Why do we need polygons? Imagine you want to draw world map. Each Polygons can represent a country, while a Polygon cannot. For example, New Zealand comprises two major islands, and you need two polygons, which is a Polygons.
#getClass("Polygons")
Srs1 = Polygons(list(Sr1), "s1")
Srs2 = Polygons(list(Sr2), "s2")
Srs3 = Polygons(list(Sr3, Sr4), "s3/4")
#getClass("SpatialPolygons")
SpP = SpatialPolygons(list(Srs1,Srs2,Srs3), 1:3)
plot(SpP, col = 1:3, bg="yellow")
Note that there is a hole in one of Polygons
#getClass("SpatialPolygons")
df = data.frame(z1 = c(1.2,1.3,1.6), z2 = c(2.2,2.8,3.9), row.names = row.names(SpP))
SpPDF = SpatialPolygonsDataFrame(Sr = SpP, data = df)
spplot(SpPDF, zcol = "z1")
The argument “row.names = row.names(SpP)” is needed.
The dataset is gmel2, and it can be downloaded at https://github.com/TedChu/90122Lab/tree/master/datasets.
library(spdep)
load("datasets/gmel2.Rdata")
R function poly2nb produces a spatial weight matrix from a SpatialPolygons(DataFrame) object.
## Convert gmel2 to SpatialPolygonsDataFrame, since the following packages require SpatialPolygonsDataFrame
gmel.sp = as(gmel2, "Spatial")
Wqueen = poly2nb(gmel.sp)
Wrook = poly2nb(gmel.sp, queen=FALSE)
plot(gmel.sp,border="grey60", axes=TRUE)
plot(Wqueen, coordinates(gmel.sp), pch=19, cex=0.6, add=TRUE,col="red")
plot(Wrook, coordinates(gmel.sp), pch=19, cex=0.6, add=TRUE)
Can you see the difference between queen rule and rook rule?
A Moran’s I test is performed on the variable price. More information about Moran’s I codes can be found in Cp1C – 8.
## plot
moran.test(x=gmel2$price, nb2listw(Wqueen), alternative="two.sided")
##
## Moran I test under randomisation
##
## data: gmel2$price
## weights: nb2listw(Wqueen)
##
## Moran I statistic standard deviate = 5.8472, p-value = 5e-09
## alternative hypothesis: two.sided
## sample estimates:
## Moran I statistic Expectation Variance
## 0.59027230 -0.03333333 0.01137440
Since the p-value < 0.05, we conclude that there is spatial autocorrelation for the house price in Greater Melbourne.
LISA is performed on price variable.
resI = localmoran(gmel2$price, nb2listw(Wqueen), alternative="two.sided")
round(head(resI),3)
## Ii E.Ii Var.Ii Z.Ii Pr(z != E(Ii))
## 1 -0.123 -0.002 0.009 -1.239 0.215
## 2 1.407 -0.100 0.864 1.621 0.105
## 3 1.927 -0.239 0.777 2.457 0.014
## 4 0.497 -0.029 0.100 1.666 0.096
## 5 0.736 -0.030 0.125 2.169 0.030
## 6 0.665 -0.038 0.194 1.596 0.111
Next, some visualisation for the above results.
####
gmellisa = gmel2
gmellisa$lisa = resI[,1]
gmellisa$pvalue = resI[,5]
### Spatial plots with LISA value
library(ggplot2)
ggplot() + geom_sf(data=gmellisa, aes(fill = lisa))
ggplot() + geom_sf(data=gmellisa, aes(fill = pvalue))
Suppose we want to know which LGAs have significant local spatial autocorrelation (\(\alpha = 0.05\)).
gmellisa$name2[gmellisa$pvalue < 0.05]
## [1] "Boroondara" "Casey" "Glen Eira" "Monash" "Port Phillip"
## [6] "Stonnington" "Yarra"
They all have positive LISA values. If you want to formally test whether there are positive local autocorrelation, you will need to change alternative to greater.
You can also highlight these cities.
gmellisa2 = gmellisa[gmellisa$pvalue < 0.05, ]
ggplot() + geom_sf(data=gmellisa, aes(fill = pvalue)) +
geom_sf(data = gmellisa2, color = "red", alpha = 0) +
geom_sf_label(data = gmellisa2, aes(label = name2))
or
library(mapview)
mapview(gmellisa, zcol = "pvalue", at = c(0, 0.01, 0.05, 0.1, 1))