Take-home Exercise 2

This take home exercise aims to investigate the distribution of Airbnb listings and how location factors affect it as well as the impact of COVID-19 pandemic on Airbnb business.

Nor Aisyah https://www.linkedin.com/in/nor-aisyah/
10-01-2021

1. Background Information

This analysis aims to investigate if the distribution of Airbnb listings are affected by location factors such as near to existing hotels, MRT services and tourist attractions and analyse the impact of COVID-19 on Airbnb business in Singapore.

2. Dataset

Note*:

3. Install and Load R packages

This code chunk performs 3 tasks:

packages <- c('sf', 'tidyverse', 'tmap', 'rgdal', 'maptools', 'raster','spatstat', 'kableExtra', 'devtools')
for(p in packages){
  if(!require(p, character.only = T)){
    install.packages(p)
  }
  library(p, character.only = T)
}
devtools::install_github("gadenbuie/xaringanExtra")
library(xaringanExtra)

More on the packages used:

4. Importing and Wrangling Geospatial Data

4.1 Import and check CRS

4.1.1 CoastalOutline

Code Chunk

sg_sf <- st_read(dsn = "data/geospatial", layer="CostalOutline")
Reading layer `CostalOutline' from data source 
  `C:\aisyahajit2018\IS415\IS415_blog\_posts\2021-10-01-take-home-exercise-2\data\geospatial' 
  using driver `ESRI Shapefile'
Simple feature collection with 60 features and 4 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: 2663.926 ymin: 16357.98 xmax: 56047.79 ymax: 50244.03
Projected CRS: SVY21

st_crs

st_crs(sg_sf)
Coordinate Reference System:
  User input: SVY21 
  wkt:
PROJCRS["SVY21",
    BASEGEOGCRS["SVY21[WGS84]",
        DATUM["World Geodetic System 1984",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]],
            ID["EPSG",6326]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["Degree",0.0174532925199433]]],
    CONVERSION["unnamed",
        METHOD["Transverse Mercator",
            ID["EPSG",9807]],
        PARAMETER["Latitude of natural origin",1.36666666666667,
            ANGLEUNIT["Degree",0.0174532925199433],
            ID["EPSG",8801]],
        PARAMETER["Longitude of natural origin",103.833333333333,
            ANGLEUNIT["Degree",0.0174532925199433],
            ID["EPSG",8802]],
        PARAMETER["Scale factor at natural origin",1,
            SCALEUNIT["unity",1],
            ID["EPSG",8805]],
        PARAMETER["False easting",28001.642,
            LENGTHUNIT["metre",1],
            ID["EPSG",8806]],
        PARAMETER["False northing",38744.572,
            LENGTHUNIT["metre",1],
            ID["EPSG",8807]]],
    CS[Cartesian,2],
        AXIS["(E)",east,
            ORDER[1],
            LENGTHUNIT["metre",1,
                ID["EPSG",9001]]],
        AXIS["(N)",north,
            ORDER[2],
            LENGTHUNIT["metre",1,
                ID["EPSG",9001]]]]

From the results above, we can see that:

4.1.2 MPSZ

Code Chunk

mpsz_sf <- st_read(dsn = "data/geospatial", layer="MP14_SUBZONE_WEB_PL")
Reading layer `MP14_SUBZONE_WEB_PL' from data source 
  `C:\aisyahajit2018\IS415\IS415_blog\_posts\2021-10-01-take-home-exercise-2\data\geospatial' 
  using driver `ESRI Shapefile'
Simple feature collection with 323 features and 15 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 2667.538 ymin: 15748.72 xmax: 56396.44 ymax: 50256.33
Projected CRS: SVY21

st_crs

st_crs(mpsz_sf)
Coordinate Reference System:
  User input: SVY21 
  wkt:
PROJCRS["SVY21",
    BASEGEOGCRS["SVY21[WGS84]",
        DATUM["World Geodetic System 1984",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]],
            ID["EPSG",6326]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["Degree",0.0174532925199433]]],
    CONVERSION["unnamed",
        METHOD["Transverse Mercator",
            ID["EPSG",9807]],
        PARAMETER["Latitude of natural origin",1.36666666666667,
            ANGLEUNIT["Degree",0.0174532925199433],
            ID["EPSG",8801]],
        PARAMETER["Longitude of natural origin",103.833333333333,
            ANGLEUNIT["Degree",0.0174532925199433],
            ID["EPSG",8802]],
        PARAMETER["Scale factor at natural origin",1,
            SCALEUNIT["unity",1],
            ID["EPSG",8805]],
        PARAMETER["False easting",28001.642,
            LENGTHUNIT["metre",1],
            ID["EPSG",8806]],
        PARAMETER["False northing",38744.572,
            LENGTHUNIT["metre",1],
            ID["EPSG",8807]]],
    CS[Cartesian,2],
        AXIS["(E)",east,
            ORDER[1],
            LENGTHUNIT["metre",1,
                ID["EPSG",9001]]],
        AXIS["(N)",north,
            ORDER[2],
            LENGTHUNIT["metre",1,
                ID["EPSG",9001]]]]

From the results above, we can see that:

4.1.3 MRT

Code Chunk

mrtlrt_sf <- st_read(dsn = "data/geospatial", layer="MRTLRTStnPtt")
Reading layer `MRTLRTStnPtt' from data source 
  `C:\aisyahajit2018\IS415\IS415_blog\_posts\2021-10-01-take-home-exercise-2\data\geospatial' 
  using driver `ESRI Shapefile'
Simple feature collection with 185 features and 3 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: 6138.311 ymin: 27555.06 xmax: 45254.86 ymax: 47854.2
Projected CRS: SVY21

st_crs

st_crs(mrtlrt_sf)
Coordinate Reference System:
  User input: SVY21 
  wkt:
PROJCRS["SVY21",
    BASEGEOGCRS["SVY21[WGS84]",
        DATUM["World Geodetic System 1984",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]],
            ID["EPSG",6326]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["Degree",0.0174532925199433]]],
    CONVERSION["unnamed",
        METHOD["Transverse Mercator",
            ID["EPSG",9807]],
        PARAMETER["Latitude of natural origin",1.36666666666667,
            ANGLEUNIT["Degree",0.0174532925199433],
            ID["EPSG",8801]],
        PARAMETER["Longitude of natural origin",103.833333333333,
            ANGLEUNIT["Degree",0.0174532925199433],
            ID["EPSG",8802]],
        PARAMETER["Scale factor at natural origin",1,
            SCALEUNIT["unity",1],
            ID["EPSG",8805]],
        PARAMETER["False easting",28001.642,
            LENGTHUNIT["metre",1],
            ID["EPSG",8806]],
        PARAMETER["False northing",38744.572,
            LENGTHUNIT["metre",1],
            ID["EPSG",8807]]],
    CS[Cartesian,2],
        AXIS["(E)",east,
            ORDER[1],
            LENGTHUNIT["metre",1,
                ID["EPSG",9001]]],
        AXIS["(N)",north,
            ORDER[2],
            LENGTHUNIT["metre",1,
                ID["EPSG",9001]]]]

From the results above, we can see that:

Since all the projected CRS for the above sf dataframes is SVY21, we need to assign them the correct EPSG code which is 3414 in the next section.

4.2 Assign EPSG code to sf dataframes and check

4.2.1 Assign EPSG code to sg_sf

Code Chunk

sg_sf <- st_set_crs(sg_sf, 3414)

st_crs

st_crs(sg_sf)
Coordinate Reference System:
  User input: EPSG:3414 
  wkt:
PROJCRS["SVY21 / Singapore TM",
    BASEGEOGCRS["SVY21",
        DATUM["SVY21",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["degree",0.0174532925199433]],
        ID["EPSG",4757]],
    CONVERSION["Singapore Transverse Mercator",
        METHOD["Transverse Mercator",
            ID["EPSG",9807]],
        PARAMETER["Latitude of natural origin",1.36666666666667,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8801]],
        PARAMETER["Longitude of natural origin",103.833333333333,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8802]],
        PARAMETER["Scale factor at natural origin",1,
            SCALEUNIT["unity",1],
            ID["EPSG",8805]],
        PARAMETER["False easting",28001.642,
            LENGTHUNIT["metre",1],
            ID["EPSG",8806]],
        PARAMETER["False northing",38744.572,
            LENGTHUNIT["metre",1],
            ID["EPSG",8807]]],
    CS[Cartesian,2],
        AXIS["northing (N)",north,
            ORDER[1],
            LENGTHUNIT["metre",1]],
        AXIS["easting (E)",east,
            ORDER[2],
            LENGTHUNIT["metre",1]],
    USAGE[
        SCOPE["Cadastre, engineering survey, topographic mapping."],
        AREA["Singapore - onshore and offshore."],
        BBOX[1.13,103.59,1.47,104.07]],
    ID["EPSG",3414]]

4.2.2 Assign EPSG code to mpsz_sf

Code Chunk

mpsz_sf <- st_set_crs(mpsz_sf, 3414)

st_crs

st_crs(mpsz_sf)
Coordinate Reference System:
  User input: EPSG:3414 
  wkt:
PROJCRS["SVY21 / Singapore TM",
    BASEGEOGCRS["SVY21",
        DATUM["SVY21",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["degree",0.0174532925199433]],
        ID["EPSG",4757]],
    CONVERSION["Singapore Transverse Mercator",
        METHOD["Transverse Mercator",
            ID["EPSG",9807]],
        PARAMETER["Latitude of natural origin",1.36666666666667,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8801]],
        PARAMETER["Longitude of natural origin",103.833333333333,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8802]],
        PARAMETER["Scale factor at natural origin",1,
            SCALEUNIT["unity",1],
            ID["EPSG",8805]],
        PARAMETER["False easting",28001.642,
            LENGTHUNIT["metre",1],
            ID["EPSG",8806]],
        PARAMETER["False northing",38744.572,
            LENGTHUNIT["metre",1],
            ID["EPSG",8807]]],
    CS[Cartesian,2],
        AXIS["northing (N)",north,
            ORDER[1],
            LENGTHUNIT["metre",1]],
        AXIS["easting (E)",east,
            ORDER[2],
            LENGTHUNIT["metre",1]],
    USAGE[
        SCOPE["Cadastre, engineering survey, topographic mapping."],
        AREA["Singapore - onshore and offshore."],
        BBOX[1.13,103.59,1.47,104.07]],
    ID["EPSG",3414]]

4.2.3 Assign EPSG code to mrtlrt_sf

Code Chunk

mrtlrt_sf <- st_set_crs(mrtlrt_sf, 3414)

st_crs

st_crs(mrtlrt_sf)
Coordinate Reference System:
  User input: EPSG:3414 
  wkt:
PROJCRS["SVY21 / Singapore TM",
    BASEGEOGCRS["SVY21",
        DATUM["SVY21",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["degree",0.0174532925199433]],
        ID["EPSG",4757]],
    CONVERSION["Singapore Transverse Mercator",
        METHOD["Transverse Mercator",
            ID["EPSG",9807]],
        PARAMETER["Latitude of natural origin",1.36666666666667,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8801]],
        PARAMETER["Longitude of natural origin",103.833333333333,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8802]],
        PARAMETER["Scale factor at natural origin",1,
            SCALEUNIT["unity",1],
            ID["EPSG",8805]],
        PARAMETER["False easting",28001.642,
            LENGTHUNIT["metre",1],
            ID["EPSG",8806]],
        PARAMETER["False northing",38744.572,
            LENGTHUNIT["metre",1],
            ID["EPSG",8807]]],
    CS[Cartesian,2],
        AXIS["northing (N)",north,
            ORDER[1],
            LENGTHUNIT["metre",1]],
        AXIS["easting (E)",east,
            ORDER[2],
            LENGTHUNIT["metre",1]],
    USAGE[
        SCOPE["Cadastre, engineering survey, topographic mapping."],
        AREA["Singapore - onshore and offshore."],
        BBOX[1.13,103.59,1.47,104.07]],
    ID["EPSG",3414]]

The CRS has now been correctly assigned for all 3 geospatial data.

4.3 Check if geometries are valid

length(which(st_is_valid(sg_sf) == FALSE))
[1] 1
length(which(st_is_valid(mpsz_sf) == FALSE))
[1] 9
length(which(st_is_valid(mrtlrt_sf) == FALSE))
[1] 0

From the results above, there are:

4.4 Handle the invalid geometries

sg_sf <- st_make_valid(sg_sf)
mpsz_sf <- st_make_valid(mpsz_sf)
length(which(st_is_valid(sg_sf) == FALSE))
[1] 0
length(which(st_is_valid(mpsz_sf) == FALSE))
[1] 0

Based on the results above, there are no longer any invalid geometries.

4.5 Mapping the geospatial layers

tm_shape(sg_sf) +
  tm_polygons() +
tm_shape(mpsz_sf) +
  tm_borders(alpha = 0.5) +
tm_shape(mrtlrt_sf) +
  tm_dots(col="red", size=0.1)

5. Importing and Wrangling Aspatial Data

5.1 Import and inspect aspatial data

5.1.1 Airbnb listings as at June 2019

Code Chunk

abb_jun19 <- read_csv("data/aspatial/30062019.csv")

glimpse

glimpse(abb_jun19)
Rows: 8,293
Columns: 16
$ id                             <dbl> 49091, 50646, 56334, 71609, 7~
$ name                           <chr> "COZICOMFORT LONG TERM STAY R~
$ host_id                        <dbl> 266763, 227796, 266763, 36704~
$ host_name                      <chr> "Francesca", "Sujatha", "Fran~
$ neighbourhood_group            <chr> "North Region", "Central Regi~
$ neighbourhood                  <chr> "Woodlands", "Bukit Timah", "~
$ latitude                       <dbl> 1.44255, 1.33235, 1.44246, 1.~
$ longitude                      <dbl> 103.7958, 103.7852, 103.7967,~
$ room_type                      <chr> "Private room", "Private room~
$ price                          <dbl> 81, 80, 68, 200, 92, 102, 203~
$ minimum_nights                 <dbl> 180, 90, 6, 1, 1, 1, 1, 7, 30~
$ number_of_reviews              <dbl> 1, 18, 20, 12, 20, 35, 23, 15~
$ last_review                    <date> 2013-10-21, 2014-12-26, 2015~
$ reviews_per_month              <dbl> 0.01, 0.28, 0.21, 0.13, 0.21,~
$ calculated_host_listings_count <dbl> 2, 1, 2, 9, 9, 9, 9, 1, 4, 4,~
$ availability_365               <dbl> 365, 365, 365, 353, 353, 348,~

5.1.2 Airbnb listings as at June 2021

Code Chunk

abb_jun21 <- read_csv("data/aspatial/listings.csv")

glimpse

glimpse(abb_jun21)
Rows: 4,238
Columns: 16
$ id                             <dbl> 49091, 50646, 56334, 71609, 7~
$ name                           <chr> "COZICOMFORT LONG TERM STAY R~
$ host_id                        <dbl> 266763, 227796, 266763, 36704~
$ host_name                      <chr> "Francesca", "Sujatha", "Fran~
$ neighbourhood_group            <chr> "North Region", "Central Regi~
$ neighbourhood                  <chr> "Woodlands", "Bukit Timah", "~
$ latitude                       <dbl> 1.44129, 1.33432, 1.44041, 1.~
$ longitude                      <dbl> 103.7957, 103.7852, 103.7967,~
$ room_type                      <chr> "Private room", "Private room~
$ price                          <dbl> 81, 80, 67, 177, 81, 81, 52, ~
$ minimum_nights                 <dbl> 180, 90, 6, 90, 90, 90, 14, 1~
$ number_of_reviews              <dbl> 1, 18, 20, 20, 24, 48, 20, 13~
$ last_review                    <date> 2013-10-21, 2014-07-08, 2015~
$ reviews_per_month              <dbl> 0.01, 0.22, 0.16, 0.29, 0.34,~
$ calculated_host_listings_count <dbl> 2, 1, 2, 4, 4, 4, 50, 50, 7, ~
$ availability_365               <dbl> 365, 365, 365, 365, 365, 365,~

5.1.3 Hotels

Code Chunk

hotels <- read.csv("data/aspatial/hotels.csv")

glimpse

glimpse(hotels)
Rows: 422
Columns: 9
$ NAME              <chr> "Jayleen Clarke Quay Hotel", "JEN Singapor~
$ ADDRESSPOSTALCODE <int> 59390, 238858, 249716, 399041, 238485, 399~
$ ADDRESSSTREETNAME <chr> "25 New Bridge Road", "277 Orchard Road , ~
$ HYPERLINK         <chr> "jayleenclarkequay@gmail.com", "singaporeo~
$ TOTALROOMS        <int> 20, 499, 565, 42, 81, 33, 17, 634, 56, 451~
$ KEEPERNAME        <chr> "James Federick Chong Kah Yean", "Kuok Oon~
$ Lat               <dbl> 1.288715, 1.300510, 1.304271, 1.311586, 1.~
$ Lng               <dbl> 103.8475, 103.8392, 103.8239, 103.8775, 10~
$ ICON_NAME         <chr> "hotel.gif", "hotel.gif", "hotel.gif", "ho~

5.1.3 Tourism

Code Chunk

tourism <- read.csv("data/aspatial/tourism.csv")

glimpse

glimpse(tourism)
Rows: 107
Columns: 17
$ NAME              <chr> "Chinatown Heritage Centre, Singapore", "T~
$ DESCRIPTION       <chr> "Experience how Singaporeâ\200\231s early ~
$ ADDRESSSTREETNAME <chr> "48 Pagoda Street", "158 Telok Ayer Street~
$ HYPERLINK         <chr> "http://www.singaporechinatown.com.sg/", "~
$ PHOTOURL          <chr> "www.yoursingapore.com/content/dam/desktop~
$ URL_PATH          <chr> "www.yoursingapore.com/en/see-do-singapore~
$ IMAGE_ALT_TEXT    <chr> "Learn more about local Chinese culture at~
$ PHOTOCREDITS      <chr> "Joel Chua DY", "Joel Chua DY", "Joel Chua~
$ LASTMODIFIED      <chr> "2015-11-02T10:16:52.847+08:00", "2015-11-~
$ LATITUDE          <dbl> 1.283510, 1.280940, 1.310070, 1.277219, 1.~
$ LONGTITUDE        <dbl> 103.8444, 103.8476, 103.8994, 103.8373, 10~
$ META_DESCRIPTION  <chr> "At the Chinatown Heritage Centre, experie~
$ OPENING_HOURS     <chr> "Daily, 9am â\200“ 8pm,Last entry at 7pm.*~
$ Lat               <dbl> 1.283510, 1.280940, 1.310070, 1.277219, 1.~
$ Lng               <dbl> 103.8444, 103.8476, 103.8994, 103.8373, 10~
$ ICON_NAME         <chr> "tourist_spot.gif", "tourist_spot.gif", "t~
$ ADDRESSPOSTALCODE <int> NA, NA, NA, 0, NA, NA, NA, NA, NA, NA, NA,~

From the above results, we can see that for:

5.2 Check for NA values

NOTE:

5.2.1 Check for NA values in abb_jun19

colSums(is.na(abb_jun19))
                            id                           name 
                             0                              2 
                       host_id                      host_name 
                             0                             82 
           neighbourhood_group                  neighbourhood 
                             0                              0 
                      latitude                      longitude 
                             0                              0 
                     room_type                          price 
                             0                              0 
                minimum_nights              number_of_reviews 
                             0                              0 
                   last_review              reviews_per_month 
                          3137                           3137 
calculated_host_listings_count               availability_365 
                             0                              0 

From the above results, we can see that there are:

5.2.2 Check for NA values in abb_jun21

colSums(is.na(abb_jun21))
                            id                           name 
                             0                              0 
                       host_id                      host_name 
                             0                              8 
           neighbourhood_group                  neighbourhood 
                             0                              0 
                      latitude                      longitude 
                             0                              0 
                     room_type                          price 
                             0                              0 
                minimum_nights              number_of_reviews 
                             0                              0 
                   last_review              reviews_per_month 
                          1759                           1759 
calculated_host_listings_count               availability_365 
                             0                              0 

From the above results, we can see that there are:

5.2.3 Check for NA values in hotels

colSums(is.na(hotels))
             NAME ADDRESSPOSTALCODE ADDRESSSTREETNAME 
                0                 0                 0 
        HYPERLINK        TOTALROOMS        KEEPERNAME 
              129                 0                 0 
              Lat               Lng         ICON_NAME 
                0                 0                 0 

5.2.4 Check for NA values in tourism

colSums(is.na(tourism))
             NAME       DESCRIPTION ADDRESSSTREETNAME 
                0                 0                 2 
        HYPERLINK          PHOTOURL          URL_PATH 
               15                12                 0 
   IMAGE_ALT_TEXT      PHOTOCREDITS      LASTMODIFIED 
               17                62                 0 
         LATITUDE        LONGTITUDE  META_DESCRIPTION 
                1                 1                 0 
    OPENING_HOURS               Lat               Lng 
               29                 0                 0 
        ICON_NAME ADDRESSPOSTALCODE 
                0                96 

5.2.4.1 Inspect NA values in tourism coordinates

Code Chunk

tourism_na <- tourism %>% 
  filter_at(vars(LONGTITUDE, LATITUDE), any_vars(is.na(.)))

5.2.4.2 Remove NA values

tourism <- tourism %>% 
  filter_at(vars(LONGTITUDE, LATITUDE), any_vars(!is.na(.)))

5.2.4.3 Check if NA value is removed

tourism_na <- tourism %>% 
  filter_at(vars(LONGTITUDE, LATITUDE), any_vars(is.na(.)))

nrow(tourism_na)
[1] 0

We can see from the above results that the row with NA value in the coordinates columns has been removed.

5.3 Convert aspatial data frame into sf objects, assign and transform CRS

abb_jun19_sf <- st_as_sf(abb_jun19,
                    coords = c("longitude", 
                               "latitude"),
                    crs=4326) %>%
  st_transform(crs = 3414)

abb_jun21_sf <- st_as_sf(abb_jun21,
                    coords = c("longitude", 
                               "latitude"),
                    crs=4326) %>%
  st_transform(crs = 3414)

hotels_sf <- st_as_sf(hotels,
                    coords = c("Lng", 
                               "Lat"),
                    crs=4326) %>%
  st_transform(crs = 3414)

tourism_sf <- st_as_sf(tourism,
                    coords = c("Lng", 
                               "Lat"),
                    crs=4326) %>%
  st_transform(crs = 3414)

5.4. Check the respective CRS

abb_jun19_sf crs

st_crs(abb_jun19_sf)
Coordinate Reference System:
  User input: EPSG:3414 
  wkt:
PROJCRS["SVY21 / Singapore TM",
    BASEGEOGCRS["SVY21",
        DATUM["SVY21",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["degree",0.0174532925199433]],
        ID["EPSG",4757]],
    CONVERSION["Singapore Transverse Mercator",
        METHOD["Transverse Mercator",
            ID["EPSG",9807]],
        PARAMETER["Latitude of natural origin",1.36666666666667,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8801]],
        PARAMETER["Longitude of natural origin",103.833333333333,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8802]],
        PARAMETER["Scale factor at natural origin",1,
            SCALEUNIT["unity",1],
            ID["EPSG",8805]],
        PARAMETER["False easting",28001.642,
            LENGTHUNIT["metre",1],
            ID["EPSG",8806]],
        PARAMETER["False northing",38744.572,
            LENGTHUNIT["metre",1],
            ID["EPSG",8807]]],
    CS[Cartesian,2],
        AXIS["northing (N)",north,
            ORDER[1],
            LENGTHUNIT["metre",1]],
        AXIS["easting (E)",east,
            ORDER[2],
            LENGTHUNIT["metre",1]],
    USAGE[
        SCOPE["Cadastre, engineering survey, topographic mapping."],
        AREA["Singapore - onshore and offshore."],
        BBOX[1.13,103.59,1.47,104.07]],
    ID["EPSG",3414]]

abb_jun21_sf crs

st_crs(abb_jun21_sf)
Coordinate Reference System:
  User input: EPSG:3414 
  wkt:
PROJCRS["SVY21 / Singapore TM",
    BASEGEOGCRS["SVY21",
        DATUM["SVY21",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["degree",0.0174532925199433]],
        ID["EPSG",4757]],
    CONVERSION["Singapore Transverse Mercator",
        METHOD["Transverse Mercator",
            ID["EPSG",9807]],
        PARAMETER["Latitude of natural origin",1.36666666666667,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8801]],
        PARAMETER["Longitude of natural origin",103.833333333333,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8802]],
        PARAMETER["Scale factor at natural origin",1,
            SCALEUNIT["unity",1],
            ID["EPSG",8805]],
        PARAMETER["False easting",28001.642,
            LENGTHUNIT["metre",1],
            ID["EPSG",8806]],
        PARAMETER["False northing",38744.572,
            LENGTHUNIT["metre",1],
            ID["EPSG",8807]]],
    CS[Cartesian,2],
        AXIS["northing (N)",north,
            ORDER[1],
            LENGTHUNIT["metre",1]],
        AXIS["easting (E)",east,
            ORDER[2],
            LENGTHUNIT["metre",1]],
    USAGE[
        SCOPE["Cadastre, engineering survey, topographic mapping."],
        AREA["Singapore - onshore and offshore."],
        BBOX[1.13,103.59,1.47,104.07]],
    ID["EPSG",3414]]

hotels_sf crs

st_crs(hotels_sf)
Coordinate Reference System:
  User input: EPSG:3414 
  wkt:
PROJCRS["SVY21 / Singapore TM",
    BASEGEOGCRS["SVY21",
        DATUM["SVY21",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["degree",0.0174532925199433]],
        ID["EPSG",4757]],
    CONVERSION["Singapore Transverse Mercator",
        METHOD["Transverse Mercator",
            ID["EPSG",9807]],
        PARAMETER["Latitude of natural origin",1.36666666666667,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8801]],
        PARAMETER["Longitude of natural origin",103.833333333333,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8802]],
        PARAMETER["Scale factor at natural origin",1,
            SCALEUNIT["unity",1],
            ID["EPSG",8805]],
        PARAMETER["False easting",28001.642,
            LENGTHUNIT["metre",1],
            ID["EPSG",8806]],
        PARAMETER["False northing",38744.572,
            LENGTHUNIT["metre",1],
            ID["EPSG",8807]]],
    CS[Cartesian,2],
        AXIS["northing (N)",north,
            ORDER[1],
            LENGTHUNIT["metre",1]],
        AXIS["easting (E)",east,
            ORDER[2],
            LENGTHUNIT["metre",1]],
    USAGE[
        SCOPE["Cadastre, engineering survey, topographic mapping."],
        AREA["Singapore - onshore and offshore."],
        BBOX[1.13,103.59,1.47,104.07]],
    ID["EPSG",3414]]

tourism_sf crs

st_crs(tourism_sf)
Coordinate Reference System:
  User input: EPSG:3414 
  wkt:
PROJCRS["SVY21 / Singapore TM",
    BASEGEOGCRS["SVY21",
        DATUM["SVY21",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["degree",0.0174532925199433]],
        ID["EPSG",4757]],
    CONVERSION["Singapore Transverse Mercator",
        METHOD["Transverse Mercator",
            ID["EPSG",9807]],
        PARAMETER["Latitude of natural origin",1.36666666666667,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8801]],
        PARAMETER["Longitude of natural origin",103.833333333333,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8802]],
        PARAMETER["Scale factor at natural origin",1,
            SCALEUNIT["unity",1],
            ID["EPSG",8805]],
        PARAMETER["False easting",28001.642,
            LENGTHUNIT["metre",1],
            ID["EPSG",8806]],
        PARAMETER["False northing",38744.572,
            LENGTHUNIT["metre",1],
            ID["EPSG",8807]]],
    CS[Cartesian,2],
        AXIS["northing (N)",north,
            ORDER[1],
            LENGTHUNIT["metre",1]],
        AXIS["easting (E)",east,
            ORDER[2],
            LENGTHUNIT["metre",1]],
    USAGE[
        SCOPE["Cadastre, engineering survey, topographic mapping."],
        AREA["Singapore - onshore and offshore."],
        BBOX[1.13,103.59,1.47,104.07]],
    ID["EPSG",3414]]

5.5. Plotting it altogether

In the code chunks below, mapping functions of tmap package is used.

5.5.1 Plot map without abb_jun21

tm_shape(sg_sf) +
  tm_polygons() +
tm_shape(mpsz_sf) +
  tm_borders(alpha = 0.5) +
  tmap_options(check.and.fix = TRUE) +
tm_shape(mrtlrt_sf) +
  tm_dots(col ="red",  size = 0.02) +
tm_shape(abb_jun19_sf) +
  tm_dots(col ="blue",  size = 0.02) +
tm_shape(hotels_sf) +
  tm_dots(col ="orange",  size = 0.02) +
tm_shape(tourism_sf) +
  tm_dots(col ="purple",  size = 0.02) +
  
tm_layout(title= 'Map of Airbnb 2019 listings with other location factors',
          title.position = c('right', 'bottom'))

5.5.2 Plot map without abb_jun19

tm_shape(sg_sf) +
  tm_polygons() +
tm_shape(mpsz_sf) +
  tm_borders(alpha = 0.5) +
  tmap_options(check.and.fix = TRUE) +
tm_shape(mrtlrt_sf) +
  tm_dots(col ="red",  size = 0.02) +
tm_shape(abb_jun21_sf) +
  tm_dots(col ="green",  size = 0.02) +
tm_shape(hotels_sf) +
  tm_dots(col ="orange",  size = 0.02) +
tm_shape(tourism_sf) +
  tm_dots(col ="purple",  size = 0.02) +
  
tm_layout(title= 'Map of Airbnb 2021 listings with other location factors',
          title.position = c('right', 'bottom'))

6. Spatial Data Wrangling

In this section, we will be converting our simple feature data frames to ppp objects for our analysis later.

6.1 Convert from sf dataframes to sp’s Spatial* Classes

abb_jun19 <- as_Spatial(abb_jun19_sf)
abb_jun21 <- as_Spatial(abb_jun21_sf)
hotels <- as_Spatial(hotels_sf)
tourism <- as_Spatial(tourism_sf)
sg <- as_Spatial(sg_sf)
mpsz <- as_Spatial(mpsz_sf)
mrtlrt <- as_Spatial(mrtlrt_sf)

6.2 Convert from Spatial* class to generic sp format

abb_jun19_sp <- as(abb_jun19, "SpatialPoints")
abb_jun21_sp <- as(abb_jun21, "SpatialPoints")
hotels_sp <- as(hotels, "SpatialPoints")
tourism_sp <- as(tourism, "SpatialPoints")
mrtlrt_sp <- as(mrtlrt, "SpatialPoints")
sg_sp <- as(sg, "SpatialPolygons")
mpsz_sp <- as(mpsz, "SpatialPolygons")

6.3 Convert from sp to spatstat ppp format

abb_jun19_ppp <- as(abb_jun19_sp, "ppp")
abb_jun21_ppp <- as(abb_jun21_sp, "ppp")
hotels_ppp <- as(hotels_sp, "ppp")
tourism_ppp <- as(tourism_sp, "ppp")
mrtlrt_ppp <- as(mrtlrt_sp, "ppp")

6.4 Summary statistics of newly created ppp objects

abb_jun19_ppp summary

summary(abb_jun19_ppp)
Planar point pattern:  8293 points
Average intensity 9.345289e-06 points per square unit

*Pattern contains duplicated points*

Coordinates are given to 3 decimal places
i.e. rounded to the nearest multiple of 0.001 units

Window: rectangle = [7215.57, 44098.31] x [25166.35, 49226.35] units
                    (36880 x 24060 units)
Window area = 887399000 square units

abb_jun21_ppp summary

summary(abb_jun21_ppp)
Planar point pattern:  4238 points
Average intensity 5.114513e-06 points per square unit

*Pattern contains duplicated points*

Coordinates are given to 3 decimal places
i.e. rounded to the nearest multiple of 0.001 units

Window: rectangle = [7406.99, 43337.89] x [25330, 48391.55] units
                    (35930 x 23060 units)
Window area = 828622000 square units

hotels_ppp summary

summary(hotels_ppp)
Planar point pattern:  422 points
Average intensity 5.58414e-07 points per square unit

*Pattern contains duplicated points*

Coordinates are given to 3 decimal places
i.e. rounded to the nearest multiple of 0.001 units

Window: rectangle = [5939.24, 45334.18] x [25379.44, 44562.4] units
                    (39390 x 19180 units)
Window area = 755712000 square units

tourism_ppp summary

summary(tourism_ppp)
Planar point pattern:  106 points
Average intensity 1.328016e-07 points per square unit

*Pattern contains duplicated points*

Coordinates are given to 3 decimal places
i.e. rounded to the nearest multiple of 0.001 units

Window: rectangle = [11380.23, 43659.54] x [22869.34, 47596.73] units
                    (32280 x 24730 units)
Window area = 798183000 square units

mrtlrt_ppp summary

summary(mrtlrt_ppp)
Planar point pattern:  185 points
Average intensity 2.32988e-07 points per square unit

Coordinates are given to 3 decimal places
i.e. rounded to the nearest multiple of 0.001 units

Window: rectangle = [6138.31, 45254.86] x [27555.06, 47854.2] units
                    (39120 x 20300 units)
Window area = 794032000 square units

From the results above:

6.4 Handling duplicates

6.4.1 Check for number of duplicated points

sum(multiplicity(abb_jun19_ppp) > 1)
[1] 6
sum(multiplicity(abb_jun21_ppp) > 1)
[1] 224
sum(multiplicity(hotels_ppp) > 1)
[1] 10
sum(multiplicity(tourism_ppp) > 1)
[1] 7
sum(multiplicity(mrtlrt_ppp) > 1)
[1] 0

6.4.2 Handling duplicates with jittering

abb_jun19_ppp_jit <- rjitter(abb_jun19_ppp, 
                             retry=TRUE, 
                             nsim=1, 
                             drop=TRUE)

abb_jun21_ppp_jit <- rjitter(abb_jun21_ppp, 
                             retry=TRUE, 
                             nsim=1, 
                             drop=TRUE)

hotels_ppp_jit <- rjitter(hotels_ppp, 
                             retry=TRUE, 
                             nsim=1, 
                             drop=TRUE)

tourism_ppp_jit <- rjitter(tourism_ppp, 
                             retry=TRUE, 
                             nsim=1, 
                             drop=TRUE)

6.4.3 Check if duplicates still exist

any(duplicated(abb_jun19_ppp_jit))
[1] FALSE
any(duplicated(abb_jun21_ppp_jit))
[1] FALSE
any(duplicated(hotels_ppp_jit))
[1] FALSE
any(duplicated(tourism_ppp_jit))
[1] FALSE

From the above results, we can confirm that there are no longer duplicates after performing the jittering approach.

6.5 Create owin objects

sg_owin <- as(sg_sp, "owin")
plot(sg_owin)

6.6 Combine point events object and owin object

The code chunk below combines the point objects of abb_jun19, abb_jun21, hotels, tourism and mrtlrt with the owin object into one ppp object class.

abb_jun19SG_ppp = abb_jun19_ppp_jit[sg_owin]
abb_jun21SG_ppp = abb_jun21_ppp_jit[sg_owin]
hotelsSG_ppp = hotels_ppp_jit[sg_owin]
tourismSG_ppp = tourism_ppp_jit[sg_owin]
mrtlrtSG_ppp = mrtlrt_ppp[sg_owin]

6.6.1 Plot ppp object within Singapore boundary

The code chunk below plots the ppp object class using plot function of base R package.

par(mfrow=c(3,2), mar=c(1,1,1,1))
plot(abb_jun19SG_ppp)
plot(abb_jun21SG_ppp)
plot(hotelsSG_ppp)
plot(tourismSG_ppp)
plot(mrtlrtSG_ppp)

6.7 Rescale to kilometers

abb_jun19SG_ppp.km <- rescale(abb_jun19SG_ppp, 1000, "km")
abb_jun21SG_ppp.km <- rescale(abb_jun21SG_ppp, 1000, "km")
hotelsSG_ppp.km <- rescale(hotelsSG_ppp, 1000, "km")
tourismSG_ppp.km <- rescale(tourismSG_ppp, 1000, "km")
mrtlrtSG_ppp.km <- rescale(mrtlrtSG_ppp, 1000, "km")

7. Section A: Airbnb Distribution in 2019

This section aims to investigate if the distribution of Airbnb listings at June 2019 are affected by location factors such as near to existing hotels, MRT services and tourist attractions. For our investigation, this section will consist of 2 parts:

  1. Exploratory Spatial Data Analysis
  1. Second-Order Spatial Point Patterns Analysis

7.1 Exploratory Spatial Data Analysis

7.1.1 KDE maps

7.1.1.1 Explore different bandwidth methods

To define the bandwidth of the density estimation, we can explore the different bandwidth methods such as:

bw_methods <- function(data) {
  cvl <- bw.CvL(data)
  scott <- bw.scott(data)
  ppl <- bw.ppl(data)
  diggle <- bw.diggle(data)
  output <- list(cvl, scott, ppl, diggle)
  names(output) <- c("CvL", "scott", "ppl", "diggle")
  print(output)
}

abb_jun19 bw

bw_methods(abb_jun19SG_ppp.km)
$CvL
   sigma 
5.700728 

$scott
  sigma.x   sigma.y 
1.0748842 0.7425303 

$ppl
    sigma 
0.2254825 

$diggle
    sigma 
0.0419688 

hotels bw

bw_methods(hotelsSG_ppp.km)
$CvL
   sigma 
9.092461 

$scott
  sigma.x   sigma.y 
1.2702643 0.7999742 

$ppl
    sigma 
0.9148847 

$diggle
     sigma 
0.08289152 

tourism bw

bw_methods(tourismSG_ppp.km)
$CvL
   sigma 
7.186458 

$scott
 sigma.x  sigma.y 
2.234335 1.889744 

$ppl
   sigma 
1.801735 

$diggle
    sigma 
0.2901203 

mrtlrt bw

bw_methods(mrtlrtSG_ppp.km)
$CvL
   sigma 
5.893095 

$scott
 sigma.x  sigma.y 
3.081230 2.104299 

$ppl
   sigma 
1.211568 

$diggle
    sigma 
0.6382647 

Based on the above results:

First, we have to understand what is the meaning of tight clusters

7.1.1.2 Plot KDE Maps of Airbnb 2019 listings, hotels, MRT services, and tourist attractions

kde_diggle <- function(data) {
  par(mfrow=c(1,2), mar=c(1,1,1,1))
  plot(density(data, sigma=bw.diggle, edge=TRUE, kernel="quartic"), main = "bw.diggle")
  plot(data, main = "Point map")
}
7.1.1.2.1 Airbnb June 2019 listings
kde_diggle(abb_jun19SG_ppp.km)

7.1.1.2.2 Hotels
kde_diggle(hotelsSG_ppp.km)

7.1.1.2.3 Tourism
kde_diggle(tourismSG_ppp.km)

7.1.1.2.4 MrtLrt
kde_diggle(mrtlrtSG_ppp.km)

From the above maps,

7.1.2 Display kernel density maps on openstreetmap of Singapore

7.1.2.1 Compute KDE maps with metres

kde_abb_jun19SG_ppp.m <- density(abb_jun19SG_ppp, sigma=bw.diggle, edge=TRUE,kernel="quartic") 
kde_hotelsSG_ppp.m <- density(hotelsSG_ppp, sigma=bw.diggle, edge=TRUE, kernel="quartic")
kde_tourismSG_ppp.m <- density(tourismSG_ppp, sigma=bw.diggle, edge=TRUE, kernel="quartic")
kde_mrtlrtSG_ppp.m <- density(mrtlrtSG_ppp, sigma=bw.diggle, edge=TRUE, kernel="quartic")

7.1.2.2 Convert KDE output into grid objects

gridded_kde_abb_jun19SG_dg <- as.SpatialGridDataFrame.im(kde_abb_jun19SG_ppp.m)
gridded_kde_hotels_dg <- as.SpatialGridDataFrame.im(kde_hotelsSG_ppp.m)
gridded_kde_tourism_dg <- as.SpatialGridDataFrame.im(kde_tourismSG_ppp.m)
gridded_kde_mrtlrt_dg <- as.SpatialGridDataFrame.im(kde_mrtlrtSG_ppp.m)

7.1.2.3 Convert gridded output into raster

kde_abb_jun19SG_dg_raster <- raster(gridded_kde_abb_jun19SG_dg)
kde_abb_jun19SG_dg_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : NA 
source     : memory
names      : v 
values     : -2.289334e-19, 0.001766134  (min, max)
kde_hotels_dg_raster <- raster(gridded_kde_hotels_dg)
kde_hotels_dg_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : NA 
source     : memory
names      : v 
values     : -2.992963e-20, 0.000190199  (min, max)
kde_tourism_dg_raster <- raster(gridded_kde_tourism_dg)
kde_tourism_dg_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : NA 
source     : memory
names      : v 
values     : -4.173818e-21, 1.775046e-05  (min, max)
kde_mrtlrt_dg_raster <- raster(gridded_kde_mrtlrt_dg)
kde_mrtlrt_dg_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : NA 
source     : memory
names      : v 
values     : -1.538645e-21, 3.368543e-06  (min, max)

From the results above:

7.1.2.4 Assign projection systems

projection(kde_abb_jun19SG_dg_raster) <- CRS("+init=EPSG:3414")
kde_abb_jun19SG_dg_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
source     : memory
names      : v 
values     : -2.289334e-19, 0.001766134  (min, max)
projection(kde_hotels_dg_raster) <- CRS("+init=EPSG:3414")
kde_hotels_dg_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
source     : memory
names      : v 
values     : -2.992963e-20, 0.000190199  (min, max)
projection(kde_tourism_dg_raster) <- CRS("+init=EPSG:3414")
kde_tourism_dg_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
source     : memory
names      : v 
values     : -4.173818e-21, 1.775046e-05  (min, max)
projection(kde_mrtlrt_dg_raster) <- CRS("+init=EPSG:3414")
kde_mrtlrt_dg_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
source     : memory
names      : v 
values     : -1.538645e-21, 3.368543e-06  (min, max)

We can see from the results above that the CRS for all Raster objects are assigned the relevant projection systems.

7.1.2.5 Visualise KDE Raster objects in OpenStreetMap

plot_oms <- function(raster1, raster2, rt_legend1, rt_legend2) {
  tmap_mode('view')
  tm_basemap("OpenStreetMap")+
    tm_shape(raster1) +
      tm_raster("v", title = rt_legend1, alpha= 0.7,  palette = "Reds" ) +
    tm_shape(raster2) + 
      tm_raster("v", title = rt_legend2, alpha= 0.7, palette = "Blues")
  
}
7.1.2.5.1 Plot Airbnb Jun2019 with Hotels
plot_oms(kde_hotels_dg_raster, kde_abb_jun19SG_dg_raster, "Hotels", "Airbnb Jun2019")
tmap_mode('plot')

Spatial patterns observations:

7.1.2.5.2 Plot Airbnb Jun2019 with Tourism
plot_oms(kde_tourism_dg_raster, kde_abb_jun19SG_dg_raster, "Tourism", "Airbnb Jun2019")
tmap_mode('plot')

Spatial patterns observations:

7.1.2.5.3 Plot Airbnb Jun2019 with MrtLrt
plot_oms(kde_mrtlrt_dg_raster, kde_abb_jun19SG_dg_raster, "MrtLrt", "Airbnb Jun2019")
tmap_mode('plot')

Spatial patterns observations:

Advantage of Kernel Density Map over Point Map:

7.1.3 Compare Spatial Point Patterns Using KDE

From the previous KDE Maps, we can observe that there are specific areas in the Central Region, such as Geylang, Kallang, Downtown Core and Rochor which have a higher density. Hence, we will look into these areas as intensive computational power is required to conduct a Second Order Analysis on all areas of Singapore.

7.1.3.1 Extract, Convert and Create Owin for Study Area

The following code chunk will:

get_study_area <- function(plsz, area) {
  plsz[plsz$PLN_AREA_N == area,] %>%
    as('Spatial') %>%
    as('SpatialPolygons') %>%
    as('owin')
}
gl_owin <- get_study_area(mpsz_sf, "GEYLANG")
kl_owin <- get_study_area(mpsz_sf, "KALLANG")
dc_owin <- get_study_area(mpsz_sf, "DOWNTOWN CORE")
rc_owin <- get_study_area(mpsz_sf, "ROCHOR")

7.1.3.2 Combining Spatial points and the study area

abbjun19_gl_ppp = abb_jun19_ppp_jit[gl_owin]
hotels_gl_ppp = hotels_ppp_jit[gl_owin]
tourism_gl_ppp = tourism_ppp_jit[gl_owin]
mrtlrt_gl_ppp = mrtlrt_ppp[gl_owin]

abbjun19_kl_ppp = abb_jun19_ppp_jit[kl_owin]
hotels_kl_ppp = hotels_ppp_jit[kl_owin]
tourism_kl_ppp = tourism_ppp_jit[kl_owin]
mrtlrt_kl_ppp = mrtlrt_ppp[kl_owin]

abbjun19_dc_ppp = abb_jun19_ppp_jit[dc_owin]
hotels_dc_ppp = hotels_ppp_jit[dc_owin]
tourism_dc_ppp = tourism_ppp_jit[dc_owin]
mrtlrt_dc_ppp = mrtlrt_ppp[dc_owin]

abbjun19_rc_ppp = abb_jun19_ppp_jit[rc_owin]
hotels_rc_ppp = hotels_ppp_jit[rc_owin]
tourism_rc_ppp = tourism_ppp_jit[rc_owin]
mrtlrt_rc_ppp = mrtlrt_ppp[rc_owin]

7.1.3.6 Rescale from metres to kilometres

abbjun19_gl_ppp.km = rescale(abbjun19_gl_ppp, 1000, "km")
hotels_gl_ppp.km = rescale(hotels_gl_ppp, 1000, "km")
tourism_gl_ppp.km = rescale(tourism_gl_ppp, 1000, "km")
mrtlrt_gl_ppp.km = rescale(mrtlrt_gl_ppp, 1000, "km")

abbjun19_kl_ppp.km = rescale(abbjun19_kl_ppp, 1000, "km")
hotels_kl_ppp.km = rescale(hotels_kl_ppp, 1000, "km")
tourism_kl_ppp.km = rescale(tourism_kl_ppp, 1000, "km")
mrtlrt_kl_ppp.km = rescale(mrtlrt_kl_ppp, 1000, "km")

abbjun19_dc_ppp.km = rescale(abbjun19_dc_ppp, 1000, "km")
hotels_dc_ppp.km = rescale(hotels_dc_ppp, 1000, "km")
tourism_dc_ppp.km = rescale(tourism_dc_ppp, 1000, "km")
mrtlrt_dc_ppp.km = rescale(mrtlrt_dc_ppp, 1000, "km")

abbjun19_rc_ppp.km = rescale(abbjun19_rc_ppp, 1000, "km")
hotels_rc_ppp.km = rescale(hotels_rc_ppp, 1000, "km")
tourism_rc_ppp.km = rescale(tourism_rc_ppp, 1000, "km")
mrtlrt_rc_ppp.km = rescale(mrtlrt_rc_ppp, 1000, "km")

7.1.3.7 Plot KDE Maps of the study area

layout(matrix(c(1,2,3,4), 2, 2, byrow = TRUE), widths=c(5,5), heights=c(5,5))
par(mfrow=c(2,2))
plot(density(abbjun19_gl_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="quartic"), main="Geylang")
plot(density(abbjun19_kl_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="quartic"), main="Kallang")
plot(density(abbjun19_dc_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="quartic"), main="Downtown Core")
plot(density(abbjun19_rc_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="quartic"), main="Rochor")

From the KDE plots above, it is easy to think that Rohor is the most dense area. However, we should not be too quick to judge as the intensity level of Rochor is lower than Downtown core and Geylang.

7.1.3.8 Plot Airbnb, Hotels, Mrt, Tourist Attraction in each area

7.1.3.8.1 Geylang
par(mfrow=c(2,2), mar=c(1,1,1,1))
plot(abbjun19_gl_ppp.km, main = "Airbnb")
plot(hotels_gl_ppp.km, main = "Hotels")
plot(mrtlrt_gl_ppp.km, main = "Mrt")
plot(tourism_gl_ppp.km, main = "Tourist Attractions")

From the plots above:

7.1.3.8.2 Kallang
par(mfrow=c(2,2), mar=c(1,1,1,1))
plot(abbjun19_kl_ppp.km, main = "Airbnb")
plot(hotels_kl_ppp.km, main = "Hotels")
plot(mrtlrt_kl_ppp.km, main = "Mrt")
plot(tourism_kl_ppp.km, main = "Tourist Attractions")

From the plots above:

7.1.3.8.3 Downtown Core
par(mfrow=c(2,2), mar=c(1,1,1,1))
plot(abbjun19_dc_ppp.km, main = "Airbnb")
plot(hotels_dc_ppp.km, main = "Hotels")
plot(mrtlrt_dc_ppp.km, main = "Mrt")
plot(tourism_dc_ppp.km, main = "Tourist Attractions")

From the plots above:

7.1.3.8.4 Rochor
par(mfrow=c(2,2), mar=c(1,1,1,1))
plot(abbjun19_rc_ppp.km, main = "Airbnb")
plot(hotels_rc_ppp.km, main = "Hotels")
plot(mrtlrt_rc_ppp.km, main = "Mrt")
plot(tourism_rc_ppp.km, main = "Tourist Attractions")

From the plots above:

Overall, below are the observations about the target areas and location factors:

7.2 Second-order Spatial Point Patterns Analysis

To draw statistical conclusions on whether the distribution of Airbnb listings are affected by location factors such as hotels, tourist attractions and MRT services, we need to perform Second-order Spatial Point Analysis.

7.2.1 Combine ppp objects

kl_ppp <- superimpose(kl_abbjun2019_mark=abbjun19_kl_ppp,
                      kl_hotels_mark=hotels_kl_ppp,
                      kl_tourism_mark=tourism_kl_ppp,
                      kl_mrtlrt_mark=mrtlrt_kl_ppp)
dc_ppp <- superimpose(dc_abbjun2019_mark=abbjun19_dc_ppp,
                                    dc_hotels_mark=hotels_dc_ppp,
                                    dc_tourism_mark=tourism_dc_ppp,
                                    dc_mrtlrt_mark=mrtlrt_dc_ppp)

7.2.2 Multi-type Point Patterns Analysis: Cross L-Function

lcross <- function(data, i, j, title) {
  compute <- Lcross(data, i, j, correction='border')
  plot(compute, . - r ~ r, xlab="d", ylab="L(d)-r", main=title)
}

7.2.2.1 Geylang

layout(matrix(c(1,2,3, 0), 2, 2, byrow = TRUE), widths=c(5,5), heights=c(5,5))
par(mfrow=c(2,2))
lcross(data = kl_ppp, i="kl_abbjun2019_mark", j="kl_hotels_mark", title="Airbnb 2019 & Hotels Lcross")
lcross(data = kl_ppp, i="kl_abbjun2019_mark", j="kl_tourism_mark", title="Airbnb 2019 & Tourism Lcross")
lcross(data = kl_ppp, i="kl_abbjun2019_mark", j="kl_mrtlrt_mark", title="Airbnb 2019 & MrtLrt Lcross")

7.2.2.2 Downtown Core

layout(matrix(c(1,2,3, 0), 2, 2, byrow = TRUE), widths=c(5,5), heights=c(5,5))
par(mfrow=c(2,2))
lcross(data = dc_ppp, i="dc_abbjun2019_mark", j="dc_hotels_mark", title="Airbnb 2019 & Hotels Lcross")
lcross(data = dc_ppp, i="dc_abbjun2019_mark", j="dc_tourism_mark", title="Airbnb 2019 & Tourism Lcross")
lcross(data = dc_ppp, i="dc_abbjun2019_mark", j="dc_mrtlrt_mark", title="Airbnb 2019 & MrtLrt Lcross")

Based on the plots of both Geylang and Downtown Core, - It shows that there is a sign that the marked spatial point events are not independent spatially. - However, a hypothesis test is required to confirm the observation statistically.

7.2.3 Performing CSR testing on the Cross L-Function

7.2.3.1 Monte Carlo test with Cross L-Function

# Geylang
abb2019_hotels_Lcross_kl.csr <- envelope(kl_ppp, Lcross,i="kl_abbjun2019_mark", j="kl_hotels_mark", correction='border', nsim=99)
Generating 99 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,  99.

Done.
abb2019_tourism_Lcross_kl.csr <- envelope(kl_ppp, Lcross,i="kl_abbjun2019_mark", j="kl_tourism_mark",correction='border', nsim=99)
Generating 99 simulations of CSR  ...
1, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
2, 3, 4, 5, 6, 7, 8, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
9, 10, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
11, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
12, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
13, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
14, 15, 16, 17, 18, 19, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
20, 21, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
22, 23, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
24, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
25, 26, 27, 28, 29, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
30, 31, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
32, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
33, 34, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
35,
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
36, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
37, 38, 39, 40, 41, 42, 43, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
44, 45, 46, 47, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
48, 49, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
50, 51, 52, 53, 54, 55, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
56, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
57, 58, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
59, 60, 61, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
62, 63, 64, 65, 66, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
67, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
68, 69, 70,
71, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
72, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
73, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
74, 75, 76, 77, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
78, 79, 80, 81, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
82, 83, 84, 85, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
86, 87, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
88, 89, 90, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
91, 92, 93, 94, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
95, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
96, 97, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
98, Error in Kcross(X, i, j, ..., correction = correction) : 
  No points have mark j = kl_tourism_mark
[retrying]
 99.

Done.
abb2019_mrtlrt_Lcross_kl.csr <- envelope(kl_ppp, Lcross,i="kl_abbjun2019_mark", j="kl_mrtlrt_mark",correction='border', nsim=99)
Generating 99 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,  99.

Done.
# Downtown Core
abb2019_hotels_Lcross_dc.csr <- envelope(dc_ppp, Lcross,i="dc_abbjun2019_mark", j="dc_hotels_mark",correction='border', nsim=99)
Generating 99 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,  99.

Done.
abb2019_tourism_Lcross_dc.csr <- envelope(dc_ppp, Lcross,i="dc_abbjun2019_mark", j="dc_tourism_mark",correction='border', nsim=99)
Generating 99 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,  99.

Done.
abb2019_mrtlrt_Lcross_dc.csr <- envelope(dc_ppp, Lcross,i="dc_abbjun2019_mark", j="dc_mrtlrt_mark",correction='border', nsim=99)
Generating 99 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,  99.

Done.

7.2.4 Plot Cross L-Function

7.2.4.1 Plot Cross L-Function for Geylang

layout(matrix(c(1,2,3, 0), 2, 2, byrow = TRUE), widths=c(5,5), heights=c(5,5))
par(mfrow=c(2,2))
plot(abb2019_hotels_Lcross_kl.csr, . -r ~ r, xlab="distance(m)")
plot(abb2019_tourism_Lcross_kl.csr, . -r ~ r, xlab="distance(m)")
plot(abb2019_mrtlrt_Lcross_kl.csr, . -r ~ r, xlab="distance(m)")

Recall how we should read the plot: - Red line represents the theoretical curve - Black line represents the observed curve - Grey shaded area represents the envelope derived based on the simulation.

For Geylang Airbnbs & Hotels:

For Geylang Airbnbs & Tourist Attractions:

For Geylang Airbnbs & Mrtlrt:

7.2.4.2 Plot Cross L-Function for Downtown Core

layout(matrix(c(1,2,3, 0), 2, 2, byrow = TRUE), widths=c(5,5), heights=c(5,5))
par(mfrow=c(2,2))
plot(abb2019_hotels_Lcross_dc.csr, . -r ~ r, xlab="distance(m)")
plot(abb2019_tourism_Lcross_dc.csr, . -r ~ r, xlab="distance(m)")
plot(abb2019_mrtlrt_Lcross_dc.csr, . -r ~ r, xlab="distance(m)")

For Downtown Core Airbnbs & Hotels:

For Downtown Core Airbnbs & Tourist Attractions:

For Downtown Core Airbnbs & MrtLrt:

To conclude this section,

8. Section B: Impact of COVID-19

8.1 Keep only required columns for analysis

keep <- c("room_type","latitude", "longtitude") # list of col names
abb_jun19 <- abb_jun19[,(names(abb_jun19) %in% keep)] #remove columns 
glimpse(abb_jun19)
Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots
  ..@ data       :'data.frame': 8293 obs. of  1 variable:
  .. ..$ room_type: chr [1:8293] "Private room" "Private room" "Private room" "Private room" ...
  ..@ coords.nrs : num(0) 
  ..@ coords     : num [1:8293, 1:2] 23825 22646 23922 41778 42057 ...
  .. ..- attr(*, "dimnames")=List of 2
  ..@ bbox       : num [1:2, 1:2] 7216 25166 44098 49226
  .. ..- attr(*, "dimnames")=List of 2
  ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
keep <- c("room_type","latitude", "longtitude") # list of col names
abb_jun21 <- abb_jun21[,(names(abb_jun21) %in% keep)] #remove columns 
glimpse(abb_jun21)
Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots
  ..@ data       :'data.frame': 4238 obs. of  1 variable:
  .. ..$ room_type: chr [1:4238] "Private room" "Private room" "Private room" "Private room" ...
  ..@ coords.nrs : num(0) 
  ..@ coords     : num [1:4238, 1:2] 23815 22646 23924 41973 42052 ...
  .. ..- attr(*, "dimnames")=List of 2
  ..@ bbox       : num [1:2, 1:2] 7407 25330 43338 48392
  .. ..- attr(*, "dimnames")=List of 2
  ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot

8.2 Determine the unique room type

The following code chunks will help us check the unique room types using unique feature of base R:

unique(abb_jun19$room_type)
[1] "Private room"    "Entire home/apt" "Shared room"    
unique(abb_jun21$room_type)
[1] "Private room"    "Entire home/apt" "Shared room"    
[4] "Hotel room"     

From the results above,

abb_jun21 <- abb_jun21[!abb_jun21$room_type == "Hotel room", ]
unique(abb_jun21$room_type)
[1] "Private room"    "Entire home/apt" "Shared room"    

8.3 Check marked field data type and convert to factor

str(abb_jun19)
Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots
  ..@ data       :'data.frame': 8293 obs. of  1 variable:
  .. ..$ room_type: chr [1:8293] "Private room" "Private room" "Private room" "Private room" ...
  ..@ coords.nrs : num(0) 
  ..@ coords     : num [1:8293, 1:2] 23825 22646 23922 41778 42057 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : NULL
  .. .. ..$ : chr [1:2] "coords.x1" "coords.x2"
  ..@ bbox       : num [1:2, 1:2] 7216 25166 44098 49226
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr [1:2] "coords.x1" "coords.x2"
  .. .. ..$ : chr [1:2] "min" "max"
  ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
  .. .. ..@ projargs: chr "+proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +to"| __truncated__
  .. .. ..$ comment: chr "PROJCRS[\"SVY21 / Singapore TM\",\n    BASEGEOGCRS[\"SVY21\",\n        DATUM[\"SVY21\",\n            ELLIPSOID["| __truncated__
str(abb_jun21)
Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots
  ..@ data       :'data.frame': 4040 obs. of  1 variable:
  .. ..$ room_type: chr [1:4040] "Private room" "Private room" "Private room" "Private room" ...
  ..@ coords.nrs : num(0) 
  ..@ coords     : num [1:4040, 1:2] 23815 22646 23924 41973 42052 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : NULL
  .. .. ..$ : chr [1:2] "coords.x1" "coords.x2"
  ..@ bbox       : num [1:2, 1:2] 7407 25330 43338 48392
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr [1:2] "coords.x1" "coords.x2"
  .. .. ..$ : chr [1:2] "min" "max"
  ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
  .. .. ..@ projargs: chr "+proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +to"| __truncated__
  .. .. ..$ comment: chr "PROJCRS[\"SVY21 / Singapore TM\",\n    BASEGEOGCRS[\"SVY21\",\n        DATUM[\"SVY21\",\n            ELLIPSOID["| __truncated__

The output above shows that room_type field is in character data type and not in factor data type as required by spatstat package. Hence, the code chunk below will be used to convert room_type field to factor data type.

abb_jun19@data$room_type <- as.factor(abb_jun19@data$room_type)
abb_jun21@data$room_type <- as.factor(abb_jun21@data$room_type)

8.4 Exploratory Spatial Data Analysis

8.4.1 Standardise colour palettes

The following code chunks will help us assign specific colours to the unique room types for us to visualise and differentiate the room types easily.

roomtype_colours = c(`Entire home/apt`='lightgreen', `Private room`='plum', `Shared room`='coral')

8.4.2 Plot Airbnb listings Maps by room_type

In Singapore, there are generally 5 regions demarcated by the Urban Redevelopment Authority of Singapore to aid in its planning efforts. The regions are identified as:

8.4.2.1 Plot Airbnb 2019 listings Map by room_type

tmap_mode("view")
tm_basemap("OpenStreetMap") +
  tm_shape(abb_jun19) +
  tm_dots(col = "room_type", 
          size = 0.02, 
          alpha = 0.8,
          palette=roomtype_colours) + 
  tm_view(text.size.variable = 1, view.legend.position = c("right", "bottom"))
tmap_mode('plot')
tm_shape(mpsz) +
  tm_borders(alpha = 0.5) +
tm_shape(abb_jun19) +
  tm_dots(col = 'room_type', 
          size = 0.5,
          palette=roomtype_colours) +
tm_facets(by="room_type")+
  tm_scale_bar() + 
  tm_layout(asp=1, outer.margins = 0) 

Spatial Pattern Observations from Airbnb listings 2019:

8.4.2.2 Plot Airbnb 2021 listings Map by room_type

tmap_mode("view")
tm_basemap("OpenStreetMap") +
  tm_shape(abb_jun21) +
  tm_dots(col = "room_type", 
          size = 0.02, 
          alpha = 0.8,
          palette=roomtype_colours) + 
  tm_view(text.size.variable = 1, view.legend.position = c("right", "bottom"))
tmap_mode('plot')
tm_shape(mpsz) +
  tm_borders(alpha = 0.5) +
tm_shape(abb_jun21) +
  tm_dots(col = 'room_type', 
          size = 0.5,
          palette=roomtype_colours) +
tm_facets(by="room_type")+
  tm_scale_bar() + 
  tm_layout(asp=1, outer.margins = 0) 

Spatial Pattern Observations from Airbnb listings 2021:

Compared to the patterns observed in 2019 listings, there are few different observations that can be made:

Comparing Spatial Pattern Observations of 2019 and 2021:

8.5 Spatial Data Wrangling

8.5.1 Converting the SpatialPointsDataFrame into ppp format

8.5.1.1 Airbnb 2019 listings

abb_jun19_ppp <- as(abb_jun19, "ppp")
plot(abb_jun19_ppp, which.marks = "room_type")

Figure above reveals that there are 3 sub-rooms in the marks list. They are: Entire home/apt, Private room and Shared room.

8.5.1.2 Airbnb 2021 listings

abb_jun21_ppp <- as(abb_jun21, "ppp")
plot(abb_jun21_ppp, which.marks = "room_type")

Figure above reveals that there are 3 sub-rooms in the marks list. They are: Entire home/apt, Private room and Shared room.

8.5.2 Summary of ppp objects

To examine the summary statistics of this spatial object, summary() of Base R will be used as shown in the code chunk below:

8.5.2.1 Summary of abb_jun19_ppp object

summary(abb_jun19_ppp)
Marked planar point pattern:  8293 points
Average intensity 9.345289e-06 points per square unit

*Pattern contains duplicated points*

Coordinates are given to 3 decimal places
i.e. rounded to the nearest multiple of 0.001 units

Multitype:
                frequency proportion    intensity
Entire home/apt      4264 0.51416860 4.805054e-06
Private room         3582 0.43193050 4.036516e-06
Shared room           447 0.05390088 5.037193e-07

Window: rectangle = [7215.57, 44098.31] x [25166.35, 49226.35] units
                    (36880 x 24060 units)
Window area = 887399000 square units

The report above reveals that for AirBnb 2019 listings, Entire home/apt is the largest room type with Airbnb listings in Singapore with a market share of 51%. This is followed by Private room and Shared room.

8.5.2.2 Summary of abb_jun21_ppp object

summary(abb_jun21_ppp)
Marked planar point pattern:  4040 points
Average intensity 4.875562e-06 points per square unit

*Pattern contains duplicated points*

Coordinates are given to 3 decimal places
i.e. rounded to the nearest multiple of 0.001 units

Multitype:
                frequency proportion    intensity
Entire home/apt      1817 0.44975250 2.192796e-06
Private room         2050 0.50742570 2.473986e-06
Shared room           173 0.04282178 2.087803e-07

Window: rectangle = [7406.99, 43337.89] x [25330, 48391.55] units
                    (35930 x 23060 units)
Window area = 828622000 square units

The report above reveals that for AirBnb 2021 listings, Private room is the largest room type with Airbnb listings in Singapore with a market share of 50%. This is followed by Entire home/apt and Shared room.

It is also important to note that both the Airbnb 2019 and 2021 spatial point objects contains duplicated points. The quality of our analysis will be compromised if we failed to resolve this data issue. Hence, we will be resolving this issue in the following code chunk.

8.5.3 Resolve duplicate issue with Jittering method

abb_jun19_ppp_jit <- rjitter(abb_jun19_ppp, retry=TRUE, nsim=1, drop=TRUE)
any(duplicated(abb_jun19_ppp_jit))
[1] FALSE
abb_jun21_ppp_jit <- rjitter(abb_jun21_ppp, retry=TRUE, nsim=1, drop=TRUE)
any(duplicated(abb_jun21_ppp_jit))
[1] FALSE

8.5.4 Creating owin

8.5.4.1 Extracting study area

dc = mpsz[mpsz@data$PLN_AREA_N == "DOWNTOWN CORE",]
plot(dc, main = "Downtown Core")

8.5.4.2 Converting the spatial point data frame into generic sp format

Code Chunk

dc_sp = as(dc, "SpatialPolygons")

str

str(dc_sp)
Formal class 'SpatialPolygons' [package "sp"] with 4 slots
  ..@ polygons   :List of 12
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 29145 28467
  .. .. .. .. .. .. ..@ area   : num 103238
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:86, 1:2] 29201 29194 29194 29193 29191 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 29145 28467
  .. .. .. ..@ ID       : chr "22"
  .. .. .. ..@ area     : num 103238
  .. .. .. ..$ comment: chr "0"
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 29392 29097
  .. .. .. .. .. .. ..@ area   : num 63665
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:116, 1:2] 29342 29343 29353 29356 29359 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 29392 29097
  .. .. .. ..@ ID       : chr "26"
  .. .. .. ..@ area     : num 63665
  .. .. .. ..$ comment: chr "0"
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 29730 29011
  .. .. .. .. .. .. ..@ area   : num 196620
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:85, 1:2] 29808 29866 29805 29747 29733 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 29730 29011
  .. .. .. ..@ ID       : chr "27"
  .. .. .. ..@ area     : num 196620
  .. .. .. ..$ comment: chr "0"
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 30126 28683
  .. .. .. .. .. .. ..@ area   : num 1070723
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:197, 1:2] 30437 30510 30511 30488 30487 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 30126 28683
  .. .. .. ..@ ID       : chr "31"
  .. .. .. ..@ area     : num 1070723
  .. .. .. ..$ comment: chr "0"
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 29707 29745
  .. .. .. .. .. .. ..@ area   : num 39438
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:36, 1:2] 29814 29807 29786 29760 29752 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 29707 29745
  .. .. .. ..@ ID       : chr "37"
  .. .. .. ..@ area     : num 39438
  .. .. .. ..$ comment: chr "0"
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 29969 29573
  .. .. .. .. .. .. ..@ area   : num 188767
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:97, 1:2] 30138 30138 30160 30140 30147 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 29969 29573
  .. .. .. ..@ ID       : chr "38"
  .. .. .. ..@ area     : num 188767
  .. .. .. ..$ comment: chr "0"
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 30806 29530
  .. .. .. .. .. .. ..@ area   : num 521201
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:32, 1:2] 30845 30794 30649 30649 30600 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 30806 29530
  .. .. .. ..@ ID       : chr "41"
  .. .. .. ..@ area     : num 521201
  .. .. .. ..$ comment: chr "0"
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 30380 29776
  .. .. .. .. .. .. ..@ area   : num 261844
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:55, 1:2] 30437 30304 30215 30214 30211 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 30380 29776
  .. .. .. ..@ ID       : chr "43"
  .. .. .. ..@ area     : num 261844
  .. .. .. ..$ comment: chr "0"
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 30938 30472
  .. .. .. .. .. .. ..@ area   : num 886955
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:299, 1:2] 31353 31355 31357 31359 31364 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 30938 30472
  .. .. .. ..@ ID       : chr "45"
  .. .. .. ..@ area     : num 886955
  .. .. .. ..$ comment: chr "0"
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 30209 30537
  .. .. .. .. .. .. ..@ area   : num 710569
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:170, 1:2] 30671 30645 30512 30444 30404 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 30209 30537
  .. .. .. ..@ ID       : chr "48"
  .. .. .. ..@ area     : num 710569
  .. .. .. ..$ comment: chr "0"
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 30528 31278
  .. .. .. .. .. .. ..@ area   : num 280175
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:131, 1:2] 30574 30568 30562 30527 30515 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 30528 31278
  .. .. .. ..@ ID       : chr "58"
  .. .. .. ..@ area     : num 280175
  .. .. .. ..$ comment: chr "0"
  .. ..$ :Formal class 'Polygons' [package "sp"] with 5 slots
  .. .. .. ..@ Polygons :List of 1
  .. .. .. .. ..$ :Formal class 'Polygon' [package "sp"] with 5 slots
  .. .. .. .. .. .. ..@ labpt  : num [1:2] 29398 28706
  .. .. .. .. .. .. ..@ area   : num 145519
  .. .. .. .. .. .. ..@ hole   : logi FALSE
  .. .. .. .. .. .. ..@ ringDir: int 1
  .. .. .. .. .. .. ..@ coords : num [1:96, 1:2] 29612 29584 29562 29545 29519 ...
  .. .. .. ..@ plotOrder: int 1
  .. .. .. ..@ labpt    : num [1:2] 29398 28706
  .. .. .. ..@ ID       : chr "62"
  .. .. .. ..@ area     : num 145519
  .. .. .. ..$ comment: chr "0"
  ..@ plotOrder  : int [1:12] 4 9 10 7 11 8 3 6 12 1 ...
  ..@ bbox       : num [1:2, 1:2] 28896 27914 31528 31714
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr [1:2] "x" "y"
  .. .. ..$ : chr [1:2] "min" "max"
  ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
  .. .. ..@ projargs: chr "+proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +to"| __truncated__
  .. .. ..$ comment: chr "PROJCRS[\"SVY21 / Singapore TM\",\n    BASEGEOGCRS[\"SVY21\",\n        DATUM[\"SVY21\",\n            ELLIPSOID["| __truncated__

8.5.4.3 Creating owin object

Code Chunk

dc_owin = as(dc_sp, "owin")

str

str(dc_owin)
List of 5
 $ type  : chr "polygonal"
 $ xrange: num [1:2] 28896 31528
 $ yrange: num [1:2] 27914 31714
 $ bdry  :List of 12
  ..$ :List of 2
  .. ..$ x: num [1:85] 29201 29192 29189 29184 29169 ...
  .. ..$ y: num [1:85] 28595 28595 28595 28595 28595 ...
  ..$ :List of 2
  .. ..$ x: num [1:115] 29342 29341 29339 29339 29338 ...
  .. ..$ y: num [1:115] 29190 29197 29202 29203 29211 ...
  ..$ :List of 2
  .. ..$ x: num [1:84] 29808 29764 29764 29766 29783 ...
  .. ..$ y: num [1:84] 28757 28784 28785 28788 28817 ...
  ..$ :List of 2
  .. ..$ x: num [1:196] 30437 30304 30215 30214 30211 ...
  .. ..$ y: num [1:196] 29517 29416 29420 29397 29397 ...
  ..$ :List of 2
  .. ..$ x: num [1:35] 29814 29815 29817 29820 29821 ...
  .. ..$ y: num [1:35] 29617 29619 29626 29636 29640 ...
  ..$ :List of 2
  .. ..$ x: num [1:96] 30138 30119 30115 30113 30095 ...
  .. ..$ y: num [1:96] 29843 29881 29878 29877 29867 ...
  ..$ :List of 2
  .. ..$ x: num [1:31] 30845 30895 30947 30968 30994 ...
  .. ..$ y: num [1:31] 29022 29099 29177 29209 29257 ...
  ..$ :List of 2
  .. ..$ x: num [1:54] 30437 30444 30445 30646 30770 ...
  .. ..$ y: num [1:54] 29517 29529 29530 29842 30034 ...
  ..$ :List of 2
  .. ..$ x: num [1:298] 31353 31352 31350 31347 31346 ...
  .. ..$ y: num [1:298] 30695 30695 30695 30695 30695 ...
  ..$ :List of 2
  .. ..$ x: num [1:169] 30671 30679 30747 30787 30819 ...
  .. ..$ y: num [1:169] 30868 30878 30965 31009 31042 ...
  ..$ :List of 2
  .. ..$ x: num [1:130] 30574 30580 30591 30601 30612 ...
  .. ..$ y: num [1:130] 31006 31014 31030 31042 31056 ...
  ..$ :List of 2
  .. ..$ x: num [1:95] 29612 29630 29636 29650 29633 ...
  .. ..$ y: num [1:95] 28665 28693 28704 28723 28733 ...
 $ units :List of 3
  ..$ singular  : chr "unit"
  ..$ plural    : chr "units"
  ..$ multiplier: num 1
  ..- attr(*, "class")= chr "unitname"
 - attr(*, "class")= chr "owin"

8.5.4.4 Combining Airbnb points and the study area

abbjun19_dc_ppp = abb_jun19_ppp_jit[dc_owin]
summary(abbjun19_dc_ppp)
Marked planar point pattern:  467 points
Average intensity 0.0001045044 points per square unit

Coordinates are given to 3 decimal places
i.e. rounded to the nearest multiple of 0.001 units

Multitype:
                frequency proportion    intensity
Entire home/apt       345 0.73875800 7.720343e-05
Private room          109 0.23340470 2.439181e-05
Shared room            13 0.02783726 2.909115e-06

Window: polygonal boundary
12 separate polygons (no holes)
            vertices      area relative.area
polygon 1         85  103238.0       0.02310
polygon 2        115   63665.0       0.01420
polygon 3         84  196620.0       0.04400
polygon 4        196 1070720.0       0.24000
polygon 5         35   39437.9       0.00883
polygon 6         96  188767.0       0.04220
polygon 7         31  521201.0       0.11700
polygon 8         54  261844.0       0.05860
polygon 9        298  886955.0       0.19800
polygon 10       169  710569.0       0.15900
polygon 11       130  280175.0       0.06270
polygon 12        95  145519.0       0.03260
enclosing rectangle: [28896.262, 31528.047] x [27914.19, 31714.21] 
units
                     (2632 x 3800 units)
Window area = 4468710 square units
Fraction of frame area: 0.447
abbjun21_dc_ppp = abb_jun21_ppp_jit[dc_owin]
summary(abbjun21_dc_ppp)
Marked planar point pattern:  243 points
Average intensity 5.437807e-05 points per square unit

Coordinates are given to 3 decimal places
i.e. rounded to the nearest multiple of 0.001 units

Multitype:
                frequency proportion    intensity
Entire home/apt       148 0.60905350 3.311915e-05
Private room           92 0.37860080 2.058758e-05
Shared room             3 0.01234568 6.713342e-07

Window: polygonal boundary
12 separate polygons (no holes)
            vertices      area relative.area
polygon 1         85  103238.0       0.02310
polygon 2        115   63665.0       0.01420
polygon 3         84  196620.0       0.04400
polygon 4        196 1070720.0       0.24000
polygon 5         35   39437.9       0.00883
polygon 6         96  188767.0       0.04220
polygon 7         31  521201.0       0.11700
polygon 8         54  261844.0       0.05860
polygon 9        298  886955.0       0.19800
polygon 10       169  710569.0       0.15900
polygon 11       130  280175.0       0.06270
polygon 12        95  145519.0       0.03260
enclosing rectangle: [28896.262, 31528.047] x [27914.19, 31714.21] 
units
                     (2632 x 3800 units)
Window area = 4468710 square units
Fraction of frame area: 0.447

8.5.4.5 Plotting Airbnb points and the study area

par(mfrow=c(1,2))
plot(abbjun19_dc_ppp)
plot(abbjun21_dc_ppp)

8.6 First Order Spatial Point Pattern Analysis

8.6.1 Plot KDE Maps

plot(density((split(rescale(abbjun19_dc_ppp, 1000))), sigma=bw.diggle, edge=TRUE, kernel="quartic"),main="KDE Maps of Airbnb 2019 Room types")
plot(density((split(rescale(abbjun21_dc_ppp, 1000))), sigma=bw.diggle, edge=TRUE, kernel="quartic"),main="KDE Maps of Airbnb 2021 Room types")

From the KDE Maps above,

8.6.2 Reveal the density of Airbnbs by room types

intensity(rescale(abbjun19_dc_ppp, 1000))
Entire home/apt    Private room     Shared room 
      77.203430       24.391808        2.909115 
intensity(rescale(abbjun21_dc_ppp, 1000))
Entire home/apt    Private room     Shared room 
     33.1191527      20.5875814       0.6713342 

The output reveals that in Downtown Core area, both the Entire home/apt rooms for Airbnb 2019 and 2021 listings has the highest density of 77.43 units per km square and 32.67 units per km square respectively. This is followed by Private Rooms for both 2019 and 2021, with 25.06 and 21.26 units per km square and Shared Rooms for both 2019 and 2021, with 2.69 and 0.67 units per km square.

8.6.5 Plot KDE Maps on openstreetmap of Singapore

8.6.5.1 Extract each room type from SpatialPointsDataFrame

abb2019_pr <- abb_jun19[abb_jun19@data$room_type == "Private room",]
abb2019_er <- abb_jun19[abb_jun19@data$room_type == "Entire home/apt",]
abb2019_sr <- abb_jun19[abb_jun19@data$room_type == "Private room",]

abb2021_pr <- abb_jun21[abb_jun21@data$room_type == "Private room",]
abb2021_er <- abb_jun21[abb_jun21@data$room_type == "Entire home/apt",]
abb2021_sr <- abb_jun21[abb_jun21@data$room_type == "Private room",]

8.6.5.2 Converting the Spatial* class into generic sp format

abb2019_pr_sp <- as(abb2019_pr, "SpatialPoints")
abb2019_er_sp <- as(abb2019_er, "SpatialPoints")
abb2019_sr_sp <- as(abb2019_sr, "SpatialPoints")

abb2021_pr_sp <- as(abb2021_pr, "SpatialPoints")
abb2021_er_sp <- as(abb2021_er, "SpatialPoints")
abb2021_sr_sp <- as(abb2021_sr, "SpatialPoints")

8.6.3.3 Converting the generic sp format into spatstat’s ppp format

abb2019_pr_ppp <- as(abb2019_pr_sp, "ppp")
abb2019_er_ppp <- as(abb2019_er_sp, "ppp")
abb2019_sr_ppp <- as(abb2019_sr_sp, "ppp")

abb2021_pr_ppp <- as(abb2021_pr_sp, "ppp")
abb2021_er_ppp <- as(abb2021_er_sp, "ppp")
abb2021_sr_ppp <- as(abb2021_sr_sp, "ppp")

8.6.3.4 Check for duplicates in each ppp’s objects

any(duplicated(abb2019_pr_ppp))
[1] FALSE
any(duplicated(abb2019_er_ppp))
[1] TRUE
any(duplicated(abb2019_sr_ppp))
[1] FALSE
any(duplicated(abb2021_pr_ppp))
[1] TRUE
any(duplicated(abb2021_er_ppp))
[1] TRUE
any(duplicated(abb2021_sr_ppp))
[1] TRUE

All ppp object except abb2019_pr_ppp and abb2019_sr_ppp have duplicates.

8.6.3.5 Handle duplicates and check again

abb2019_pr_ppp_jit <- rjitter(abb2019_pr_ppp, retry=TRUE, nsim=1, drop=TRUE)
abb2019_er_ppp_jit <- rjitter(abb2019_er_ppp, retry=TRUE, nsim=1, drop=TRUE)
abb2019_sr_ppp_jit <- rjitter(abb2019_sr_ppp, retry=TRUE, nsim=1, drop=TRUE)

abb2021_pr_ppp_jit <- rjitter(abb2021_pr_ppp, retry=TRUE, nsim=1, drop=TRUE)
abb2021_er_ppp_jit <- rjitter(abb2021_er_ppp, retry=TRUE, nsim=1, drop=TRUE)
abb2021_sr_ppp_jit <- rjitter(abb2021_sr_ppp, retry=TRUE, nsim=1, drop=TRUE)

any(duplicated(abb2019_pr_ppp_jit))
[1] FALSE
any(duplicated(abb2019_er_ppp_jit))
[1] FALSE
any(duplicated(abb2019_sr_ppp_jit))
[1] FALSE
any(duplicated(abb2021_pr_ppp_jit))
[1] FALSE
any(duplicated(abb2021_er_ppp_jit))
[1] FALSE
any(duplicated(abb2021_sr_ppp_jit))
[1] FALSE

8.6.3.6 Combining point events object and owin object

abb2019_pr_ppp = abb2019_pr_ppp_jit[sg_owin]
abb2019_er_ppp = abb2019_er_ppp_jit[sg_owin]
abb2019_sr_ppp = abb2019_sr_ppp_jit[sg_owin]

abb2021_pr_ppp = abb2021_pr_ppp_jit[sg_owin]
abb2021_er_ppp = abb2021_er_ppp_jit[sg_owin]
abb2021_sr_ppp = abb2021_sr_ppp_jit[sg_owin]

8.6.3.7 Compute KDE

kde_abb2019_pr_bw <- density(abb2019_pr_ppp, sigma=bw.diggle, edge=TRUE, kernel="quartic")
kde_abb2019_er_bw <- density(abb2019_er_ppp, sigma=bw.diggle, edge=TRUE, kernel="quartic")
kde_abb2019_sr_bw <- density(abb2019_sr_ppp, sigma=bw.diggle, edge=TRUE, kernel="quartic")

kde_abb2021_pr_bw <- density(abb2021_pr_ppp, sigma=bw.diggle, edge=TRUE, kernel="quartic")
kde_abb2021_er_bw <- density(abb2021_er_ppp, sigma=bw.diggle, edge=TRUE, kernel="quartic")
kde_abb2021_sr_bw <- density(abb2021_sr_ppp, sigma=bw.diggle, edge=TRUE, kernel="quartic")

8.6.3.8 Convert KDE output into grid object

gridded_kde_abb2019_pr_bw <- as.SpatialGridDataFrame.im(kde_abb2019_pr_bw)
gridded_kde_abb2019_er_bw <- as.SpatialGridDataFrame.im(kde_abb2019_er_bw)
gridded_kde_abb2019_sr_bw <- as.SpatialGridDataFrame.im(kde_abb2019_sr_bw)

gridded_kde_abb2021_pr_bw <- as.SpatialGridDataFrame.im(kde_abb2021_pr_bw)
gridded_kde_abb2021_er_bw <- as.SpatialGridDataFrame.im(kde_abb2021_er_bw)
gridded_kde_abb2021_sr_bw <- as.SpatialGridDataFrame.im(kde_abb2021_sr_bw)

8.6.3.9 Convert grid object into raster and assign project system

kde_abb2019_pr_bw_raster <- raster(gridded_kde_abb2019_pr_bw)
kde_abb2019_er_bw_raster <- raster(gridded_kde_abb2019_er_bw)
kde_abb2019_sr_bw_raster <- raster(gridded_kde_abb2019_sr_bw)
projection(kde_abb2019_pr_bw_raster) <- CRS("+init=EPSG:3414")
projection(kde_abb2019_er_bw_raster) <- CRS("+init=EPSG:3414")
projection(kde_abb2019_sr_bw_raster) <- CRS("+init=EPSG:3414")

kde_abb2021_pr_bw_raster <- raster(gridded_kde_abb2021_pr_bw)
kde_abb2021_er_bw_raster <- raster(gridded_kde_abb2021_er_bw)
kde_abb2021_sr_bw_raster <- raster(gridded_kde_abb2021_sr_bw)
projection(kde_abb2021_pr_bw_raster) <- CRS("+init=EPSG:3414")
projection(kde_abb2021_er_bw_raster) <- CRS("+init=EPSG:3414")
projection(kde_abb2021_sr_bw_raster) <- CRS("+init=EPSG:3414")

Check that Raster has been assigned correct CRS:

kde_abb2019_pr_bw_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
source     : memory
names      : v 
values     : -1.197734e-19, 0.0008313512  (min, max)
kde_abb2019_er_bw_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
source     : memory
names      : v 
values     : -1.74862e-19, 0.001358564  (min, max)
kde_abb2019_sr_bw_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
source     : memory
names      : v 
values     : -1.006599e-19, 0.0008043117  (min, max)
kde_abb2021_pr_bw_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
source     : memory
names      : v 
values     : -1.458615e-19, 0.0007245677  (min, max)
kde_abb2021_er_bw_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
source     : memory
names      : v 
values     : -7.325024e-20, 0.0003351125  (min, max)
kde_abb2021_sr_bw_raster
class      : RasterLayer 
dimensions : 128, 128, 16384  (nrow, ncol, ncell)
resolution : 417.0614, 264.7348  (x, y)
extent     : 2663.926, 56047.79, 16357.98, 50244.03  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=1.36666666666667 +lon_0=103.833333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
source     : memory
names      : v 
values     : -1.488199e-19, 0.0007517389  (min, max)

8.6.3.10 Visualise output in openstreetmap

8.6.3.10.1 Private Room Airbnb 2019 and 2021
plot_oms(kde_abb2019_pr_bw_raster, kde_abb2021_pr_bw_raster, "Private Room 2019", "Private Room 2021")
tmap_mode('plot')

Spatial patterns observed:

8.6.3.10.2 Entire home/apt Airbnb 2019 and 2021
plot_oms(kde_abb2019_er_bw_raster, kde_abb2021_er_bw_raster, "Entire home/apt 2019", "Entire home/apt 2021")
tmap_mode('plot')

Spatial patterns observed:

8.6.3.10.3 Shared Room Airbnb 2019 and 2021
plot_oms(kde_abb2019_sr_bw_raster, kde_abb2021_sr_bw_raster, "Shared Room 2019", "Shared Room 2021")
tmap_mode('plot')

Spatial patterns observed:

8.7 Second-order Spatial Point Patterns Analysis

8.7.1 Combine ppp objects with owin object

abb2019_pr_ppp_dc = abb2019_pr_ppp_jit[dc_owin]
abb2019_er_ppp_dc = abb2019_er_ppp_jit[dc_owin]
abb2019_sr_ppp_dc = abb2019_sr_ppp_jit[dc_owin]

abb2021_pr_ppp_dc = abb2021_pr_ppp_jit[dc_owin]
abb2021_er_ppp_dc = abb2021_er_ppp_jit[dc_owin]
abb2021_sr_ppp_dc = abb2021_sr_ppp_jit[dc_owin]

8.7.2 Combine ppp objects

dc_ppp_s2 <- superimpose(abb2019_pr_dc_mark=abb2019_pr_ppp_dc,
                      abb2019_er_dc_mark=abb2019_er_ppp_dc,
                      abb2019_sr_dc_mark=abb2019_sr_ppp_dc,
                      
                      abb2021_pr_dc_mark=abb2021_pr_ppp_dc,
                      abb2021_er_dc_mark=abb2021_er_ppp_dc,
                      abb2021_sr_dc_mark=abb2021_sr_ppp_dc)

8.7.3 Multi-type Point Patterns Analysis: Cross L-Function

layout(matrix(c(1,2,3,4,5,6), 3, 2, byrow = TRUE), widths=c(7,7), heights=c(7,7))
par(mfrow=c(3,2))
lcross(data = dc_ppp_s2, i="abb2019_pr_dc_mark", j="abb2019_er_dc_mark", title="PR 2019 & ER 2019")
lcross(data = dc_ppp_s2, i="abb2019_pr_dc_mark", j="abb2019_sr_dc_mark", title="PR 2019 & SR 2019")
lcross(data = dc_ppp_s2, i="abb2019_sr_dc_mark", j="abb2019_er_dc_mark", title="SR 2019 & ER 2019")

lcross(data = dc_ppp_s2, i="abb2021_pr_dc_mark", j="abb2021_er_dc_mark", title="PR 2021 & ER 2021")
lcross(data = dc_ppp_s2, i="abb2021_pr_dc_mark", j="abb2021_sr_dc_mark", title="PR 2021 & SR 2021")
lcross(data = dc_ppp_s2, i="abb2021_sr_dc_mark", j="abb2021_er_dc_mark", title="SR 2021 & ER 2021")

Based on the plots above,

8.7.4 Performing CSR testing on the Cross L-Function

8.7.4.1 Monte Carlo test with Cross L-Function

abb2019pr_abb2019er_Lcross_dc.csr <- envelope(dc_ppp_s2, Lcross,
                                               i="abb2019_pr_dc_mark", j="abb2019_er_dc_mark",
                                              correction='border', nsim=99)
Generating 99 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,  99.

Done.
abb2019pr_abb2019sr_Lcross_dc.csr <- envelope(dc_ppp_s2, Lcross,
                                               i="abb2019_pr_dc_mark", j="abb2019_sr_dc_mark",
                                              correction='border', nsim=99)
Generating 99 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,  99.

Done.
abb2019sr_abb2019er_Lcross_dc.csr <- envelope(dc_ppp_s2, Lcross,
                                               i="abb2019_sr_dc_mark", j="abb2019_er_dc_mark",
                                              correction='border', nsim=99)
Generating 99 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,  99.

Done.
abb2021pr_abb2021er_Lcross_dc.csr <- envelope(dc_ppp_s2, Lcross,
                                               i="abb2021_pr_dc_mark", j="abb2021_er_dc_mark",
                                              correction='border', nsim=99)
Generating 99 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,  99.

Done.
abb2021pr_abb2021sr_Lcross_dc.csr <- envelope(dc_ppp_s2, Lcross,
                                               i="abb2021_pr_dc_mark", j="abb2021_sr_dc_mark",
                                              correction='border', nsim=99)
Generating 99 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,  99.

Done.
abb2021sr_abb2021er_Lcross_dc.csr <- envelope(dc_ppp_s2, Lcross,
                                               i="abb2021_sr_dc_mark", j="abb2021_er_dc_mark",
                                              correction='border', nsim=99)
Generating 99 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, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,  99.

Done.

8.7.5 Plot Cross L-Function

layout(matrix(c(1,2,3,4,5,6), 3, 2, byrow = TRUE), widths=c(7,7), heights=c(7,7))
par(mfrow=c(3,2))
plot(abb2019pr_abb2019er_Lcross_dc.csr, . -r ~ r, xlab="distance(m)")
plot(abb2019pr_abb2019sr_Lcross_dc.csr, . -r ~ r, xlab="distance(m)")
plot(abb2019sr_abb2019er_Lcross_dc.csr, . -r ~ r, xlab="distance(m)")

plot(abb2021pr_abb2021er_Lcross_dc.csr, . -r ~ r, xlab="distance(m)")
plot(abb2021pr_abb2021sr_Lcross_dc.csr, . -r ~ r, xlab="distance(m)")
plot(abb2021sr_abb2021er_Lcross_dc.csr, . -r ~ r, xlab="distance(m)")

8.7.6 Conclusions for Second-order Point Patterns Analysis: Cross L-Function

8.7.6.1 Private rooms and Entire home/apt rooms 2019 vs 2021

For Airbnb 2019 Private rooms & Airbnb 2019 Entire home/apt rooms:

For Airbnb 2021 Private rooms & Airbnb 2021 Entire home/apt rooms:

8.7.6.2 Private rooms and Shared rooms 2019 vs 2021

For Airbnb 2019 Private rooms & Airbnb 2019 Shared rooms:

For Airbnb 2021 Private rooms & Airbnb 2021 Shared rooms:

8.7.6.3 Shared rooms and Entire home/apt rooms 2019 vs 2021

For Airbnb 2019 Shared rooms & Airbnb 2019 Entire home/apt rooms:

For Airbnb 2021 Shared rooms & Airbnb 2021 Entire home/apt rooms:

Comparing the 2019 and 2021 listings by room types,

9. Conclusion for Section A and B

Overall, the spatial patterns observed may be due to how near these Airbnb listings are to the location factors. As Airbnb are commonly used by tourists, tourists may choose to stay in Airbnb that are more convenient for them to travel around Singapore. Hence due to the demand, there are more listings around the Center and South regions of Singapore which are also where the tourist attractions or hotspots are in Singapore.

Additionally, for Singaporeans who may want to find an Airbnb to stay temporarily, likely because of moving houses or having a staycation. Hence, if they were to find an Airbnb to stay in, it is most likely near Town/CBD or the South regions as it is more convenient for them to go to work or again, where the shopping paradise is or places of interest are at.

As for the COVID 19 Impact on Airbnbs, we saw for ourselves that there are generally lesser Airbnb listings in 2021 as compared to 2019. This might be due to the travel restrictions where tourists are not able to enter Singapore anymore and also the COVID-19 regulations where the owners of the Airbnbs are less willing to rent out their rooms because of the fear of the rising cases. Also, since the distances for Downtown Core has dropped significantly as seen from the different room types of Airbnb listings in 2021, based on this sample, we can say that we can safely conclude that COVID-19 has made it much more difficult for Airbnb business to operate in Singapore.

10. References