Take-home Exercise 1

Author

Tan Wen Yang

Published

January 30, 2023

Modified

February 12, 2023

1.0 Introduction

This analysis aims to take a look at all the functional and non-functional water points in Osun State, Nigeria. By looking at the location of the functional and non-functional water points, we will be able to determine which clusters require immediate rehabilitation and whether these clusters are statistically significant. The analysis will comprise of three parts: Exploratory analysis, Second order spatial analysis and Spatial Correlation Analysis among the functional and non-functional water points.

2.0 Load all the relevant packages

pacman::p_load(sf, tmap, tidyverse, maptools, raster, spatstat, tmap, funModeling)

3.0 Load the Geospatial data from Humanitarian Data Exchange

Data Needed:

Dataset Source
WPdx+ (Aspatial) https://data.waterpointdata.org/dataset/Water-Point-Data-Exchange-Plus-WPdx-/eqje-vguj/data
Humanitarian Data Exchange (Geospatial) https://data.humdata.org/

We filter out everything else that is unnecessary outside of Osun

NGA_wp_geo <- st_read(dsn = "data/geospatial", 
                layer = "nga_admbnda_adm2_osgof_20190417") %>% filter(ADM1_EN == "Osun") %>% st_transform(crs=26392)
Reading layer `nga_admbnda_adm2_osgof_20190417' from data source 
  `D:\Documents\IS415-GAA-WY\take-home-ex\take-home-ex01\data\geospatial' 
  using driver `ESRI Shapefile'
Simple feature collection with 774 features and 16 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 2.668534 ymin: 4.273007 xmax: 14.67882 ymax: 13.89442
Geodetic CRS:  WGS 84
Note

From the above, we can tell that Nigeria is currently in WGS84

4.0 Get information from Nigeria -> OSUN state only

Note

For our analysis, we are only looking for Osun state, so we’ll filter out unnecessary states at this stage

nga_wp_as <- read_csv("data/aspatial/nga_wp.csv") %>%
  filter(`#clean_country_name` == "Nigeria", `#clean_adm1` == "Osun")

4.1 Check for duplicated rows

NGA_wp_geo$ADM2_EN[duplicated(NGA_wp_geo$ADM2_EN)==TRUE]
character(0)
Note

There are no duplicate rows, as we have filtered out only Osun States

4.2 Convert water point data into sf point features

We need to convert the aspatial data into an sf dataframe

Below function, we will create sfc object from existing wkt column

nga_wp_as$Geometry = st_as_sfc(nga_wp_as$`New Georeferenced Column`)
nga_wp_as
# A tibble: 5,745 × 75
   row_id `#source`      #lat_…¹ #lon_…² #repo…³ #stat…⁴ #wate…⁵ #wate…⁶ #wate…⁷
    <dbl> <chr>            <dbl>   <dbl> <chr>   <chr>   <chr>   <chr>   <chr>  
 1 225950 Federal Minis…    7.43    4.26 05/05/… Yes     Boreho… Well    Hand P…
 2 225524 Federal Minis…    7.78    4.56 04/22/… Yes     Protec… Well    Hand P…
 3 197014 Federal Minis…    7.49    4.53 04/30/… Yes     Boreho… Well    Mechan…
 4 225173 Federal Minis…    7.93    4.73 05/02/… Yes     Boreho… Well    Hand P…
 5 225843 Federal Minis…    7.74    4.44 05/08/… Yes     Boreho… Well    Hand P…
 6 235508 Federal Minis…    7.15    4.64 04/27/… Yes     Protec… Well    Hand P…
 7 197708 Federal Minis…    7.87    4.72 05/13/… Yes     Boreho… Well    Mechan…
 8 195041 Federal Minis…    7.73    4.45 06/17/… Yes     Protec… Spring  <NA>   
 9 225222 Federal Minis…    7.81    4.15 05/14/… Yes     Protec… Spring  Mechan…
10 460770 GRID3             7.4     4.33 06/13/… Unknown Boreho… Well    <NA>   
# … with 5,735 more rows, 66 more variables: `#water_tech_category` <chr>,
#   `#facility_type` <chr>, `#clean_country_name` <chr>, `#clean_adm1` <chr>,
#   `#clean_adm2` <chr>, `#clean_adm3` <chr>, `#clean_adm4` <chr>,
#   `#install_year` <dbl>, `#installer` <chr>, `#rehab_year` <lgl>,
#   `#rehabilitator` <lgl>, `#management_clean` <chr>, `#status_clean` <chr>,
#   `#pay` <chr>, `#fecal_coliform_presence` <chr>,
#   `#fecal_coliform_value` <dbl>, `#subjective_quality` <chr>, …

4.3 Convert into table into sf object using the original wgs 84 coordinate system

wp_sf <- st_sf(nga_wp_as, crs=4326)

This function will convert it into Nigeria’s projected coordinate system

wp_sf <- wp_sf %>%
  st_transform(crs = 26392)

5.0 Data Wrangling and Plotting of Water Point Data

Considering that we are mapping out the functional and non-functional water points, we will check the number of status clean and non status clean.

freq(data = wp_sf,
     input = '#status_clean')

              #status_clean frequency percentage cumulative_perc
1                Functional      2406      41.88           41.88
2            Non-Functional      2086      36.31           78.19
3                      <NA>       748      13.02           91.21
4  Functional, needs repair       259       4.51           95.72
5       Non-Functional, dry       159       2.77           98.49
6    Functional, not in use        64       1.11           99.60
7  Abandoned/Decommissioned        15       0.26           99.86
8 Functional but not in use         8       0.14          100.00

5.1 Rename column name from #status clean to status_clean and replace na with ‘unknown’ tag

Need to prepend dplyr because raster has a similar function

wp_sf_nga <- wp_sf %>% 
  rename(status_clean = '#status_clean') %>%
  rename(clean_adm2 = '#clean_adm2') %>%
  dplyr::select(status_clean, clean_adm2) %>%
  mutate(status_clean = replace_na(
    status_clean, "unknown"))

5.2 Extract functional and non-functional water points

wp_functional <- wp_sf_nga %>%
  filter(status_clean %in%
           c("Functional",
             "Functional but not in use",
             "Functional but needs repair"))

wp_nonfunctional <- wp_sf_nga %>%
  filter(status_clean %in%
           c("Abandoned/Decommissioned",
             "Abandoned",
             "Non-Functional due to dry season",
             "Non-Functional",
             "Non functional due to dry season"))

wp_unknown <- wp_sf_nga %>%
  filter(status_clean == "unknown")

5.3 Remove all unused or unneeded columns:

NGA_wp_geo <- NGA_wp_geo %>%
  dplyr::select(c(3:4, 8:9, ))

5.4 Performing Point-in-Polygon count

NGA_wp_count <- NGA_wp_geo %>% 
  mutate(`total_wp` = lengths(
    st_intersects(NGA_wp_geo, wp_sf_nga))) %>%
  mutate(`wp_functional` = lengths(
    st_intersects(NGA_wp_geo, wp_functional))) %>%
  mutate(`wp_nonfunctional` = lengths(
    st_intersects(NGA_wp_geo, wp_nonfunctional))) %>%
  mutate(`wp_unknown` = lengths(
    st_intersects(NGA_wp_geo, wp_unknown)))

6.0 Deriving the Proportion of Functional to Non-Functional Water points

The visualization would be more effective as percentage would give a better story as to how many functional water points there are compared to non-functional and vice-versa. This can also be used as an anchor for our comparison later with our KDE maps and second-order spatial analysis.

NGA_wp_count <- NGA_wp_count %>%
  mutate(pct_functional = wp_functional/total_wp) %>%
  mutate(pct_nonfunctional = wp_nonfunctional/total_wp)
tm_shape(NGA_wp_count) +
  tm_fill("pct_functional",
          n = 10,
          style = "equal",
          palette = "Blues",
          legend.hist = TRUE) +
  tm_borders(lwd = 0.1,
             alpha = 1) +
  tm_layout(main.title = "Rate map of functional water point by LGAs in Osun",
            legend.outside = TRUE)

tm_shape(NGA_wp_count) +
  tm_fill("pct_nonfunctional",
          n = 10,
          style = "equal",
          palette = "Blues",
          legend.hist = TRUE) +
  tm_borders(lwd = 0.1,
             alpha = 1) +
  tm_layout(main.title = "Rate map of non-functional water point by LGAs in Osun",
            legend.outside = TRUE)

6.1 Mapping all the water points on the map

tmap_mode('view') +
  tm_shape(wp_sf_nga) +
  tm_dots(col="status_clean",
          size=0.01,
          border.lwd=0.5) + 
  tm_view(set.zoom.limits = c(9,16))

7.0 Deriving the Kernel Density Maps of Functional/Non-Functional Water points

Convert sf dataframes into spatial class

wp_func_spatial_class <- as_Spatial(wp_functional)
wp_nfunc_spatial_class <- as_Spatial(wp_nonfunctional)
wp_osun <- as_Spatial(NGA_wp_geo)

7.1 Check the type to convert to

Tip

All are spatial points except wp_osun with is polygon

wp_func_spatial_class
class       : SpatialPointsDataFrame 
features    : 2414 
extent      : 177285.9, 290751, 343128.1, 450859.7  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4 +lon_0=8.5 +k=0.99975 +x_0=670553.98 +y_0=0 +a=6378249.145 +rf=293.465 +towgs84=-92,-93,122,0,0,0,0 +units=m +no_defs 
variables   : 2
names       :              status_clean, clean_adm2 
min values  :                Functional,   Aiyedade 
max values  : Functional but not in use,     Osogbo 
wp_nfunc_spatial_class
class       : SpatialPointsDataFrame 
features    : 2101 
extent      : 180539, 290546.5, 340054.1, 450780.1  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4 +lon_0=8.5 +k=0.99975 +x_0=670553.98 +y_0=0 +a=6378249.145 +rf=293.465 +towgs84=-92,-93,122,0,0,0,0 +units=m +no_defs 
variables   : 2
names       :             status_clean, clean_adm2 
min values  : Abandoned/Decommissioned,   Aiyedade 
max values  :           Non-Functional,     Osogbo 
wp_osun
class       : SpatialPolygonsDataFrame 
features    : 30 
extent      : 176503.2, 291043.8, 331434.7, 454520.1  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4 +lon_0=8.5 +k=0.99975 +x_0=670553.98 +y_0=0 +a=6378249.145 +rf=293.465 +towgs84=-92,-93,122,0,0,0,0 +units=m +no_defs 
variables   : 4
names       :  ADM2_EN, ADM2_PCODE, ADM1_EN, ADM1_PCODE 
min values  : Aiyedade,   NG030001,    Osun,      NG030 
max values  :   Osogbo,   NG030030,    Osun,      NG030 

7.2 Convert into generic sp format

wp_func_sp <- as(wp_func_spatial_class, "SpatialPoints")
wp_nfunc_sp <- as(wp_nfunc_spatial_class, "SpatialPoints")
wp_osun_sp <- as(wp_osun, "SpatialPolygons")

7.3 Convert the generic format into spatstat’s ppp format

wp_func_ppp <- as(wp_func_sp, "ppp")
wp_nfunc_ppp <- as(wp_nfunc_sp, "ppp")

7.4 Plot Planar Point

plot(wp_func_sp)

7.5 Summary Statistics

summary(wp_func_ppp)
Planar point pattern:  2414 points
Average intensity 1.974841e-07 points per square unit

Coordinates are given to 2 decimal places
i.e. rounded to the nearest multiple of 0.01 units

Window: rectangle = [177285.9, 290750.96] x [343128.1, 450859.7] units
                    (113500 x 107700 units)
Window area = 12223800000 square units
summary(wp_nfunc_ppp)
Planar point pattern:  2101 points
Average intensity 1.724859e-07 points per square unit

Coordinates are given to 2 decimal places
i.e. rounded to the nearest multiple of 0.01 units

Window: rectangle = [180538.96, 290546.54] x [340054.1, 450780.1] units
                    (110000 x 110700 units)
Window area = 12180700000 square units

Check for duplicated points

any(duplicated(wp_func_ppp))
[1] FALSE
any(duplicated(wp_nfunc_ppp))
[1] FALSE

No duplicate points identified.

7.6 Creating the Osun Confines using owin object

osun_owin <- as(wp_osun_sp, "owin")
plot(osun_owin)

7.7 Combine Functional and Non-Functional Point Events Object and Owin Object

wp_func_ppp_comb = wp_func_ppp[osun_owin]
wp_nfunc_ppp_comb = wp_nfunc_ppp[osun_owin]
summary(wp_func_ppp_comb)
Planar point pattern:  2316 points
Average intensity 2.681826e-07 points per square unit

Coordinates are given to 2 decimal places
i.e. rounded to the nearest multiple of 0.01 units

Window: polygonal boundary
30 separate polygons (no holes)
            vertices      area relative.area
polygon 1        204 766084000       0.08870
polygon 2         81 304399000       0.03520
polygon 3         97 465688000       0.05390
polygon 4        124 373051000       0.04320
polygon 5         60 149473000       0.01730
polygon 6         84 144820000       0.01680
polygon 7         50 102243000       0.01180
polygon 8         72 216002000       0.02500
polygon 9        112 269897000       0.03130
polygon 10       125 365142000       0.04230
polygon 11        83 111191000       0.01290
polygon 12       126 192557000       0.02230
polygon 13       219 904397000       0.10500
polygon 14       174 741131000       0.08580
polygon 15        81 138742000       0.01610
polygon 16        65 119452000       0.01380
polygon 17        90 280205000       0.03240
polygon 18        69  69814600       0.00808
polygon 19        69  42727500       0.00495
polygon 20        49  30458800       0.00353
polygon 21        62 263505000       0.03050
polygon 22        93 438930000       0.05080
polygon 23        87 274127000       0.03170
polygon 24       105 509979000       0.05910
polygon 25        98 292058000       0.03380
polygon 26        64 327765000       0.03800
polygon 27       133 108945000       0.01260
polygon 28       122 462169000       0.05350
polygon 29        94 109715000       0.01270
polygon 30        95  61239800       0.00709
enclosing rectangle: [176503.22, 291043.82] x [331434.7, 454520.1] units
                     (114500 x 123100 units)
Window area = 8635910000 square units
Fraction of frame area: 0.613

8.0 Plot functional and non-functional points

par(mfrow=c(1,2))
plot(wp_func_ppp_comb)
plot(wp_nfunc_ppp_comb)

8.1 Deriving the Kernel Density Map

kde_wp_func_map <- density(wp_func_ppp_comb,
                              sigma=bw.diggle,
                              edge=TRUE,
                            kernel="gaussian") 
kde_wp_nfunc_map <- density(wp_nfunc_ppp_comb,
                              sigma=bw.diggle,
                              edge=TRUE,
                            kernel="gaussian") 
par(mfrow=c(1,2))
plot(kde_wp_func_map)
plot(kde_wp_nfunc_map)

8.2 Rescale to KM

wp_func_ppp_comb.km <- rescale(wp_func_ppp_comb, 1000, "km")
wp_nfunc_ppp_comb.km <- rescale(wp_nfunc_ppp_comb, 1000, "km")

8.3 Rerun Density for both functional and non-functional water point:

kde_wp_func_map.bw <- density(wp_func_ppp_comb.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

kde_wp_nfunc_map.bw <- density(wp_nfunc_ppp_comb.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian")
par(mfrow=c(1,2))
plot(kde_wp_func_map.bw)
plot(kde_wp_nfunc_map.bw)

8.4 Computing Kernel Density Estimation using automatic bandwidth selection method

From our hands-on exercise, we were given the choice of either using bw.ppl or bw.diggle or adaptive kernel density estimatation method. We were told that bw.ppl is recommended specifically if the patterns are comprised of mostly tight clusters and well-distributed, and adaptive density are used if the data points are sparse. From my observation during the plotting of the water points, there appears to be a few tight clusters all throughout Osun and appear to be well-distributed. In lieu of that observation, I will be going with bw.ppl algorithm to determine the fixed bandwidth.

So, I will go with bw.ppl in this case.

kde_wp_func_map.ppl <- density(wp_func_ppp_comb.km, sigma=bw.ppl, edge=TRUE, kernel="gaussian")
kde_wp_nfunc_map.ppl <- density(wp_nfunc_ppp_comb.km, sigma=bw.ppl, edge=TRUE, kernel="gaussian")

8.5 KDE Functional Points

plot(kde_wp_func_map.ppl, main = "bw.ppl")

8.6 KDE Non-Functional Points

plot(kde_wp_nfunc_map.ppl, main = "bw.ppl")

8.7 Convert KDE output into Grid object

gridded_kde_wp_func_ppl <- as.SpatialGridDataFrame.im(kde_wp_func_map.ppl)
gridded_kde_wp_nfunc_ppl <- as.SpatialGridDataFrame.im(kde_wp_nfunc_map.ppl)
spplot(gridded_kde_wp_func_ppl)

spplot(gridded_kde_wp_nfunc_ppl)

8.8 Rasterise Layer so it can be mapped on tmap

kde_wp_func_map_ppl_raster <- raster(gridded_kde_wp_func_ppl)
kde_wp_nfunc_map_ppl_raster <- raster(gridded_kde_wp_nfunc_ppl)

Check the RASTER

kde_wp_func_map_ppl_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 0.8948485, 0.9616045  (x, y)
extent     : 176.5032, 291.0438, 331.4347, 454.5201  (xmin, xmax, ymin, ymax)
crs        : NA 
source     : memory
names      : v 
values     : -9.008439e-16, 15.26599  (min, max)
kde_wp_nfunc_map_ppl_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 0.8948485, 0.9616045  (x, y)
extent     : 176.5032, 291.0438, 331.4347, 454.5201  (xmin, xmax, ymin, ymax)
crs        : NA 
source     : memory
names      : v 
values     : -4.018365e-16, 9.797343  (min, max)

Assign Nigeria Projection System (ESG: 26392)

projection(kde_wp_func_map_ppl_raster) <- CRS("+init=EPSG:26392 +units=km")
projection(kde_wp_nfunc_map_ppl_raster) <- CRS("+init=EPSG:26392 +units=km")

8.9 Visualize functional/non-functional water point map output in TMAP:

  tm_basemap("OpenStreetMap") +
  tmap_mode('plot') + 
  tm_shape(kde_wp_func_map_ppl_raster) +
  tm_raster("v") +
  tm_layout(legend.position = c("right", "bottom"), 
            frame = FALSE, 
            main.title="Functional Water Points",
            main.title.position = "center",
            main.title.size = 1)+
  tm_view(set.zoom.limits = c(12,16))

  tm_basemap("OpenStreetMap") +
  tmap_mode('plot') + 
  tm_shape(kde_wp_nfunc_map_ppl_raster) +
  tm_raster("v") +
  tm_layout(legend.position = c("right", "bottom"), 
            frame = FALSE, 
            main.title="Non-Functional Water Points",
            main.title.position = "center",
            main.title.size = 1)+
  tm_view(set.zoom.limits = c(12,16))

10.0 Describe the spatial patterns revealed by the kernel density maps.

From the maps above, we can tell at first glance that the functional water points and non-functional water points are concentrated at a few points. Another interesting point of note are that most of the water point areas, regardless of functioning/non-functioning are situated on the northern side of the map, with one large cluster of non-functional water points at the center of Osun.

The last observation is there are more clusters of non-functioning water points compared to functioning ones.

11.0 Highlight the advantage of kernel density map over point map.

We will define the point plot of both the functional and non-functional water points to compare visualization.

tmap_mode('view') +
  tm_shape(wp_functional) +
  tm_dots(col="status_clean",
          size=0.01,
          border.lwd=0.5) + 
  tm_view(set.zoom.limits = c(9,16))
tmap_mode('view') +
  tm_shape(NGA_wp_geo) +
  tm_polygons() +
  tm_shape(wp_nonfunctional) +
  tm_dots(col="status_clean",
          size=0.01,
          border.lwd=0.5) + 
  tm_view(set.zoom.limits = c(9,16))
tmap_mode('view') +
  tm_shape(NGA_wp_geo) +
  tm_borders() +
  tm_shape(wp_sf_nga) +
  tm_dots(col="status_clean",
          size=0.01,
          border.lwd=0.5) + 
  tm_view(set.zoom.limits = c(9,16))

From one look at the point map, it’s not immediately obvious where the clusters are as the water points are generally well-distributed across Osun. It is only after we look at the kernel density map that it becomes obvious and clearer that the functional water points are mostly concentrated on the north west of Osun, with small clusters of non-functional water points scattered throughout. This also supports our earlier exploratory analysis where it’s revealed that Ede North and Ejigbo has a higher proportion of functioning water points, and central areas like Ife Central and Ifelodon are lacking functional ones.

From this map, we can prioritise areas that would need to be fixed, and also to investigate why certain LGA’s have a higher cluster/proportion of non-functioning water points compared to others.

11.0 Second Order Spatial Point Patterns Analysis

Now that we have completed our spatial data analysis, it’s time we look at some of the areas where there are particularly high clusters of functioning and non-functioning water points and determine whether their clusters are statistically significant or not.

For this, I have chosen two states each as identified in the kernel density map for areas with high cluster of functioning and non-functioning water points. We will also use the G function across the entire state of Osun to confirm that all (both functioning and non-functioning) water point’s cluster are statistically significant.

Functioning:

  1. Ejigbo
  2. Ede North

Non-Functioning:

  1. Ifelodun
  2. Ife Central

Hypothesis:

H0: The distribution of the water points are random and evenly spaced

H1: The distribution of the water points are not randomly distributed and clustered

Confidence Level: 95%; Significance level: 5%/0.05

12.0 Create our Owin Object for all the LGAs

ejigbo_area = wp_osun[wp_osun$ADM2_EN == 'Ejigbo',] %>%
  as('SpatialPolygons') %>%
  as('owin')

ede_north_area = wp_osun[wp_osun$ADM2_EN == 'Ede North',]%>%
  as('SpatialPolygons') %>%
  as('owin')

ifelodun_area = wp_osun[wp_osun$ADM2_EN == 'Ifelodun',]%>%
  as('SpatialPolygons') %>%
  as('owin')

ife_central_area = wp_osun[wp_osun$ADM2_EN == 'Ife Central',]%>%
  as('SpatialPolygons') %>%
  as('owin')
par(mfrow=c(2,2))
plot(ejigbo_area, main="Ejigbo")
plot(ede_north_area, main="Ede North")
plot(ifelodun_area, main="Ifelodun")
plot(ife_central_area, main="Ife Central")

12.1 Extract the relevant areas for the functioning/non-functioning water points

#Functioning Water points
wp_func_ejigbo_ppp = wp_func_ppp[ejigbo_area]
wp_func_ede_north_ppp = wp_func_ppp[ede_north_area]

#Non-functioning
wp_nfunc_ifelodun_ppp = wp_nfunc_ppp[ifelodun_area]
wp_nfunc_ife_central_ppp = wp_nfunc_ppp[ife_central_area]

12.2 Rescale them

wp_func_ejigbo_ppp.km = rescale(wp_func_ejigbo_ppp, 1000, "km")
wp_func_ede_north_ppp.km = rescale(wp_func_ede_north_ppp, 1000, "km")
wp_nfunc_ifelodun_ppp.km = rescale(wp_nfunc_ifelodun_ppp, 1000, "km")
wp_nfunc_ife_central_ppp.km = rescale(wp_nfunc_ife_central_ppp, 1000, "km")

12.3 Functioning Water points

par(mfrow=c(1,2))
plot(wp_func_ejigbo_ppp.km, main="Ejigbo")
plot(wp_func_ede_north_ppp.km, main="Ede North")

12.4 Non-functioning Water point

par(mfrow=c(1,2))
plot(wp_nfunc_ifelodun_ppp.km, main="Ifelodun")
plot(wp_nfunc_ife_central_ppp.km, main="Ife Central")

13.0 Using the G Function for Functioning Water Points

We will use the G Function, Gest(), to measure the distribution of the spatial point patterns, in this case, our water points. If the lines are outside of the envelop, we can say that it’s statistically significant with 95% confidence.

13.1 Ejigbo Study Area

G_ejigbo = Gest(wp_func_ejigbo_ppp.km, correction="best")
plot(G_ejigbo)

13.2 Complete Spatial Randomness Test

G_ejigbo.csr <- envelope(wp_func_ejigbo_ppp.km, Gest, nsim = 39)
Generating 39 simulations of CSR  ...
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,  39.

Done.
plot(G_ejigbo.csr)

We can say that the distribution of functional water points are clustered as they increase rapidly within a short distance of 0.5km and that it’s statistically significant as it lies outside the envelope.

13.3 Ede North Study Area:

G_ede_north = Gest(wp_func_ede_north_ppp.km, correction="best")
plot(G_ede_north)

13.4 Complete Spatial Randomness Test

G_ede_north.csr <- envelope(wp_func_ede_north_ppp.km, Gest, nsim = 39)
Generating 39 simulations of CSR  ...
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,  39.

Done.
plot(G_ede_north.csr)

Similar results to the Ede North. The functioning water points are all clustered and statistically significant. We reject the null hypothesis that they are randomly distributed and evenly spaced.

Overall results seems to indicate that functioning water points are generally clustered around certain places. This indicates that there might be practical/geographical reasons why the functioning water points are placed at where they are.

14.0 Using the G Function for Non-Functioning Water Points

14.1 Ifelodun Study Area

G_ifelodun = Gest(wp_nfunc_ifelodun_ppp.km, correction="best")
plot(G_ifelodun)

14.2 Complete Spatial Randomness Test

G_ifelodun.csr <- envelope(wp_nfunc_ifelodun_ppp.km, Gest, nsim = 39)
Generating 39 simulations of CSR  ...
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,  39.

Done.
plot(G_ifelodun.csr)

14.3 Ife Central Study Area

G_ife_central_area = Gest(wp_nfunc_ife_central_ppp.km, correction="best")
plot(G_ife_central_area)

14.4 Complete Spatial Randomness Test

G_ife_central_area.csr <- envelope(wp_nfunc_ife_central_ppp.km, Gest, nsim = 39)
Generating 39 simulations of CSR  ...
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,  39.

Done.
plot(G_ife_central_area.csr)

From the above results, we can say that the distribution of non-functioning water points are also clustered and not randomly distributed. Which means there might be external reasons why non-functioning water points are clustered at these areas. We reject the null hypothesis that they are randomly distributed and evenly spaced.

15.0 Running on the entire Osun State by including the Functioning and Non-functioning Water Points:

15.1 Creating the PPP and Owin object

wp_ppp <- as_Spatial(wp_sf_nga) %>%
  as("SpatialPoints") %>%
  as("ppp")
wp_ppp = wp_ppp[osun_owin]
wp_ppp.km = rescale(wp_ppp, 1000, "km")

We’ll now perform the G Function across the entire Osun state to confirm our hypothesis that the water points are clustered in general.

G_osun_state = Gest(wp_ppp.km, correction="best")

15.2 Plot

plot(G_osun_state)

G_osun_state.csr <- envelope(wp_ppp.km, Gest, nsim = 39)
Generating 39 simulations of CSR  ...
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,  39.

Done.

15.3 Plot the Envelop

plot(G_osun_state.csr)

15.4 G-Function on Functioning Water Points

G_osun_state_func.csr <- envelope(wp_func_ppp_comb.km, Gest, nsim = 39)
Generating 39 simulations of CSR  ...
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,  39.

Done.
plot(G_osun_state_func.csr)

15.5 G-Function on Non-Functioning Water Points

G_osun_state_nfunc.csr <- envelope(wp_nfunc_ppp_comb.km, Gest, nsim = 39)
Generating 39 simulations of CSR  ...
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,  39.

Done.
plot(G_osun_state_nfunc.csr)

From the above analysis we can say for certain that all the water points in Osun state are clustered and statistically significant as we reject the null hypothesis that they are randomly and evenly distributed. Again, the reason why this could be the case is the same as above, in that there could potentially be practical/geographical reasons why the water points are placed there.

Reasons could be there are natural water sources such as rivers, quarries and reservoirs at these areas or these areas are heavily populated with people, and the water points are built close to residential areas.

16.0 Spatial Correlation Analysis

To confirm whether the spatial distribution of functional and non-functional water points are independent, we will be using the L-Function for correlation analysis. We will applying this over the entire Osun state with both functional and non-functional water points combined.

  • H0: The functional and non-functional water points are distributed randomly and spatially independent

  • H1: The functional and non-functional water points are distributed non-random and spatially dependent.

  • Confidence Level: 95%

Null hypothesis will be rejected.

17.0 Run the L-Function on Osun State:

We’ll now perform the L Function across the entire Osun state using the PPP and owin object we’ve created earlier.

L_osun_state = Lest(wp_ppp.km, correction="Ripley")
plot(L_osun_state, . -r ~ r, 
     ylab= "L(d)-r", xlab = "d(km)")

17.1 Complete Spatial Randomness Test

L_osun_state.csr <- envelope(wp_ppp.km, Lest, nsim = 39, rank = 1, glocal=TRUE)

17.2 Plot the Envelop

plot(L_osun_state.csr, . - r ~ r, xlab="d(km)", ylab="L(d)-r")

From the combined functional and non-functional water points. We can say with statistical certainty that the functional and non-functional points are clustered close to each other, as from the graph the distance is so small that it can’t even be seen and are spatially dependent on each other. Therefore we reject the null hypothesis that the water points are distributed randomly and spatially independent from each other.

This finding ties in with the earlier cluster analysis using the G-Function that there might be practical/geographical reasons why they are spatially dependent and clustered in certain areas. Reasons can include having water points close to residential areas or close to natural water sources such as rivers, quarries or reservoirs.

Acknowledgement:

Thanks to Prof. Kam for the resources on his hands-on and in-class exercises that assisted in the completion of this take home exercise!

Referenced the Spatstat book for advice on which functions to use.