Overview

Task: Analyse the distribution of Airbnb Airbnb listing by using appropriate spatial point patterns analysis techniques. We will be performing 2 different analysis: Nation wide analysis and Planning Subzone analysis.

Within the dataset, the Airbnb listings are categorized into the following home types: - Entire place: Guests have the whole place to themselves. This usually includes a bedroom, a bathroom, and a kitchen. Hosts should note in the description if they’ll be on the property (e.g. “Host occupies ground floor of the home”) - Private room: Guests have their own private room for sleeping. Other areas could be shared. - Shared room: Guests sleep in a bedroom or a common area that could be shared with others. - Hotel room: Hotels listed on airbnb

Installing and Loading the R packages

packages = c('rgdal', 'maptools', 'raster','spatstat', 'tmap','dplyr', 'sf', 'spdep', 'tmap', 'tidyverse','ggthemes','ggplot2','plotly')
for (p in packages){
if(!require(p, character.only = T)){
install.packages(p)
}
library(p,character.only = T)
}

Data Wrangling

Importing data

Import listing data

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

Import Singapore’s coastline

sg <- readOGR(dsn = "data/geospatial/CostalOutline", layer="CostalOutline")
## OGR data source with driver: ESRI Shapefile 
## Source: "C:\Year 3\term 3\gis\Take hom assignments\Take-home_Ex02\data\geospatial\CostalOutline", layer: "CostalOutline"
## with 60 features
## It has 4 fields

Import Singapore’s subzones

mpsz <- readOGR(dsn = "data/geospatial/master-plan-2014-subzone-boundary-web-shp", layer="MP14_SUBZONE_WEB_PL")
## OGR data source with driver: ESRI Shapefile 
## Source: "C:\Year 3\term 3\gis\Take hom assignments\Take-home_Ex02\data\geospatial\master-plan-2014-subzone-boundary-web-shp", layer: "MP14_SUBZONE_WEB_PL"
## with 323 features
## It has 15 fields

Check list of header names

We only want to keep long, lat and room type for further analysis

head(listing)
## # A tibble: 6 x 16
##      id name  host_id host_name neighbourhood_g~ neighbourhood latitude
##   <dbl> <chr>   <dbl> <chr>     <chr>            <chr>            <dbl>
## 1 49091 COZI~  266763 Francesca North Region     Woodlands         1.44
## 2 50646 Plea~  227796 Sujatha   Central Region   Bukit Timah       1.33
## 3 56334 COZI~  266763 Francesca North Region     Woodlands         1.44
## 4 71609 Ensu~  367042 Belinda   East Region      Tampines          1.35
## 5 71896 B&B ~  367042 Belinda   East Region      Tampines          1.35
## 6 71903 Room~  367042 Belinda   East Region      Tampines          1.35
## # ... with 9 more variables: longitude <dbl>, room_type <chr>,
## #   price <dbl>, minimum_nights <dbl>, number_of_reviews <dbl>,
## #   last_review <date>, reviews_per_month <dbl>,
## #   calculated_host_listings_count <dbl>, availability_365 <dbl>

Remove unwanted columns in listing

listing_final = subset(listing, select = c(latitude,longitude,room_type))
listing_final
## # A tibble: 7,713 x 3
##    latitude longitude room_type   
##       <dbl>     <dbl> <chr>       
##  1     1.44      104. Private room
##  2     1.33      104. Private room
##  3     1.44      104. Private room
##  4     1.35      104. Private room
##  5     1.35      104. Private room
##  6     1.35      104. Private room
##  7     1.34      104. Private room
##  8     1.39      104. Private room
##  9     1.32      104. Private room
## 10     1.32      104. Private room
## # ... with 7,703 more rows

Check for NA values

listing_final[rowSums(is.na(listing_final))!=0,]
## # A tibble: 0 x 3
## # ... with 3 variables: latitude <dbl>, longitude <dbl>, room_type <chr>

Converting the spatial point data frame into generic sp format

Convert to sf object by using lat and long as the coordinate values. We then convert it to a Spatial Dataframe

listing_sf <- st_as_sf(listing_final, coords = c("longitude","latitude"))
listing_sf4326 <- st_set_crs(listing_sf,4326)
listing_sf3414 <- st_transform(listing_sf4326,crs=3414)

Nation-wide analysis

Exploratory Spatial Data Analysis

tmap_mode("view")
tm_basemap("OpenStreetMap")+
  tm_shape(listing_sf3414)+
  tm_dots(col = "room_type", alpha = 0.7, id = "neighbourhood")

At one glance,we can see the overall airbnb listings’ locations in Singapore. Among the 4 room types, we can see that Entire home/apt and Private room are more common in Singapore as compared to Hotel room and Shared room. Next, we will look at the 4 room types to better visualise each room type’s locations seperately.

tm_basemap("OpenStreetMap")+
tm_shape(sg) +
  tm_borders(alpha = 0.5) +
tm_shape(listing_sf3414) +
  tm_dots(col = 'room_type', id="SUBZONE_n") +
tm_facets(by="room_type", sync= TRUE)

For Entire home room type, the airbnb listings are located all around Singapore, and are scattered mostly in the central,southand southeast of Singapore such as Balestier, Tanjong Pagar, Outram, Raffles place, Aljunied, Nicoll Highway and Fort Canning. For Hotel room room type, they are located in the central and south of Singapore such as Chinatown, Clark Quay, Balestier, Whampoa, Bendeemeer and Bugis. For Private room room type, they are located all around Singapore with mostly scattered around the central, south and southeast of Singapore such as Geylang, Bugis, Somerset, Tanjong Pagar and Chinatown. For Shared room room type, they are scattered sparsely around singpore, with most located in the South and Central of Singapore such as Bendeemeer, Little India, Bugis, Chinatown and Clark Quay.

tmap_mode('plot')

Converting the spatial point data frame into generic sp format

listing_ogr <- as_Spatial(listing_sf3414)
sg_sp <- as(sg, "SpatialPolygons")

Converting the generic sp format into spatstat’s ppp format

Now, we will use as.ppp() function to convert the spatial data into spatstat’s ppp object format.

listing_ppp <- as(listing_ogr, "ppp")
plot(listing_ppp)

Handling duplicated spatial point events

any(duplicated(listing_ppp))
## [1] TRUE

Before proceeding with any analysis, we need to check if there are any duplicated points, which in this case there are.

sum(multiplicity(listing_ppp) > 1)
## [1] 230

As seen above, there are 230 duplicated spatial point events. Hence, We will perform jittering methd to add a small pertubation to split the duplicate values into nearby locations.

listing_ppp_jit <- rjitter(listing_ppp, retry=TRUE, nsim=1, drop=TRUE)

Next, we check if there are still any duplicated point events.

any(duplicated(listing_ppp_jit))
## [1] FALSE

Creating owin

sg_owin <- as(sg_sp, "owin")
listing_ppp = listing_ppp_jit[sg_owin]
summary(listing_ppp)
## Marked planar point pattern:  7713 points
## Average intensity 1.030129e-05 points per square unit
## 
## Coordinates are given to 3 decimal places
## i.e. rounded to the nearest multiple of 0.001 units
## 
## marks are of type 'character'
## Summary:
##    Length     Class      Mode 
##      7713 character character 
## 
## Window: polygonal boundary
## 60 separate polygons (no holes)
##             vertices        area relative.area
## polygon 1         38 1.56140e+04      2.09e-05
## polygon 2        735 4.69093e+06      6.27e-03
## polygon 3         49 1.66986e+04      2.23e-05
## polygon 4         76 3.12332e+05      4.17e-04
## polygon 5       5141 6.36179e+08      8.50e-01
## polygon 6         42 5.58317e+04      7.46e-05
## polygon 7         67 1.31354e+06      1.75e-03
## polygon 8         15 4.46420e+03      5.96e-06
## polygon 9         14 5.46674e+03      7.30e-06
## polygon 10        37 5.26194e+03      7.03e-06
## polygon 11        53 3.44003e+04      4.59e-05
## polygon 12        74 5.82234e+04      7.78e-05
## polygon 13        69 5.63134e+04      7.52e-05
## polygon 14       143 1.45139e+05      1.94e-04
## polygon 15       165 3.38736e+05      4.52e-04
## polygon 16       130 9.40465e+04      1.26e-04
## polygon 17        19 1.80977e+03      2.42e-06
## polygon 18        16 2.01046e+03      2.69e-06
## polygon 19        93 4.30642e+05      5.75e-04
## polygon 20        90 4.15092e+05      5.54e-04
## polygon 21       721 1.92795e+06      2.57e-03
## polygon 22       330 1.11896e+06      1.49e-03
## polygon 23       115 9.28394e+05      1.24e-03
## polygon 24        37 1.01705e+04      1.36e-05
## polygon 25        25 1.66227e+04      2.22e-05
## polygon 26        10 2.14507e+03      2.86e-06
## polygon 27       190 2.02489e+05      2.70e-04
## polygon 28       175 9.25904e+05      1.24e-03
## polygon 29      1993 9.99217e+06      1.33e-02
## polygon 30        38 2.42492e+04      3.24e-05
## polygon 31        24 6.35239e+03      8.48e-06
## polygon 32        53 6.35791e+05      8.49e-04
## polygon 33        41 1.60161e+04      2.14e-05
## polygon 34        22 2.54368e+03      3.40e-06
## polygon 35        30 1.08382e+04      1.45e-05
## polygon 36       327 2.16921e+06      2.90e-03
## polygon 37       111 6.62927e+05      8.85e-04
## polygon 38        90 1.15991e+05      1.55e-04
## polygon 39        98 6.26829e+04      8.37e-05
## polygon 40       415 3.25384e+06      4.35e-03
## polygon 41       222 1.51142e+06      2.02e-03
## polygon 42       107 6.33039e+05      8.45e-04
## polygon 43         7 2.48299e+03      3.32e-06
## polygon 44        17 3.28303e+04      4.38e-05
## polygon 45        26 8.34758e+03      1.11e-05
## polygon 46       177 4.67446e+05      6.24e-04
## polygon 47        16 3.19460e+03      4.27e-06
## polygon 48        15 4.87296e+03      6.51e-06
## polygon 49        66 1.61841e+04      2.16e-05
## polygon 50       149 5.63430e+06      7.53e-03
## polygon 51       609 2.62570e+07      3.51e-02
## polygon 52         8 7.82256e+03      1.04e-05
## polygon 53       976 2.33447e+07      3.12e-02
## polygon 54        55 8.25379e+04      1.10e-04
## polygon 55       976 2.33447e+07      3.12e-02
## polygon 56        61 3.33449e+05      4.45e-04
## polygon 57         6 1.68410e+04      2.25e-05
## polygon 58         4 9.45963e+03      1.26e-05
## polygon 59        46 6.99702e+05      9.35e-04
## polygon 60        13 7.00873e+04      9.36e-05
## enclosing rectangle: [2663.93, 56047.79] x [16357.98, 50244.03] units
##                      (53380 x 33890 units)
## Window area = 748741000 square units
## Fraction of frame area: 0.414

Quadrat Analysis

Before we perform any analysis with Quadrat analysis, lets analyse if it is suitable for our dataset. We will use the function quadratcount to split our Singapore map into quadrats and count the number of observations. More information on the function can be found via http://search.r-project.org/library/spatstat/html/plot.quadratcount.html

#First plot the points
plot(listing_ppp,pch=16,cex=0.5, main="Airbnb listings across Singapore")
#now count the points in that fall in a 6 x 6 grid overlaid across the window
plot(quadratcount(listing_ppp, nx = 6, ny = 6),add=T,col="red")

#run the quadrat count
Qcount<-data.frame(quadratcount(listing_ppp, nx = 6, ny = 6))
#put the results into a data frame
QCountTable <- data.frame(table(Qcount$Freq, exclude=NULL))
#view the data frame
QCountTable
##    Var1 Freq
## 1     0   13
## 2     1    3
## 3     3    2
## 4    35    1
## 5    37    1
## 6    41    1
## 7    56    1
## 8    72    1
## 9    76    1
## 10  130    1
## 11  144    1
## 12  148    1
## 13  275    1
## 14  295    1
## 15 1123    1
## 16 2171    1
## 17 3101    1

As seen from above, by using 6 by 6, there are a total of 13 quadrats that do not have any observations. In order to counter too many areas with 0, we increase the size of each quadrant.

#First plot the points
plot(listing_ppp,pch=16,cex=0.5, main="Airbnb listings across Singapore")
#now count the points in that fall in a 6 x 6 grid overlaid across the window
plot(quadratcount(listing_ppp, nx = 5, ny = 5),add=T,col="red")

#run the quadrat count
Qcount<-data.frame(quadratcount(listing_ppp, nx = 5, ny = 5))
#put the results into a data frame
QCountTable <- data.frame(table(Qcount$Freq, exclude=NULL))
#view the data frame
QCountTable
##    Var1 Freq
## 1     0    8
## 2     4    1
## 3    11    1
## 4    32    1
## 5    55    1
## 6    60    1
## 7   114    1
## 8   157    1
## 9   172    1
## 10  274    1
## 11  514    1
## 12  551    1
## 13 1245    1
## 14 4524    1

Even after decreasing it to 5 by 5, there are still 8 areas with 0 observations. If we were to increase the size of the quadrats once again, we will risk generalizing the patterns in the areas. Hence, we will not use quadrat analysis. Instead, we will use nearest neighbour.

Nearest Neighbour Analysis

Ho = The distribution of airbnb listings in Singapore are randomly distributed.
H1= The distribution of airbnb listings in Singapore are not randomly distributed.
Confidence interval: 99.9% (1000 simulations being run)

The null hypothesis will be rejected if p-value is smaller than alpha value of 0.001.

clarkevans.test(listing_ppp,
                correction="none",
                clipregion="sg_owin",
                alternative=c("two.sided"),
                nsim=999)
## 
##  Clark-Evans test
##  No edge correction
##  Monte Carlo test based on 999 simulations of CSR with fixed n
## 
## data:  listing_ppp
## R = 0.34229, p-value = 0.002
## alternative hypothesis: two-sided

As the p-value of 0.002 is more than the alpha value of 0.001, we do not reject the null hypothesis at 0.001 significance level. The Nearest Neighbour Index value - R value of 0.34213 i less than 1. Hence, it indicates that the pattern exhbits clustering. Next we will be analysing by room type.

Kernel Density Estimation of Airbnb listing by room type

Extract Airbnb listing by room type

Print the room type in order to obtain the exact text to filter it by

unique(listing_ogr$room_type)
## [1] "Private room"    "Entire home/apt" "Shared room"     "Hotel room"

Extract room type = Private room

Filter data that are private room

listing_pr_ppp <- subset(listing_ppp, marks == "Private room")

Extract room type = Entire home/apt

Filter data that are Entire home/apt

listing_eh_ppp <- subset(listing_ppp, marks == "Entire home/apt")

Extract room type = Shared room

Filter data that are Shared room

listing_sr_ppp <- subset(listing_ppp, marks == "Shared room")

Extract room type = Hotel room

Filter data that are Hotel room

listing_hr_ppp <- subset(listing_ppp, marks == "Hotel room")

Computing kernel density estimation by room type

Before we proceed, we will check if there are enough observations for each room type to perform kde analysis as it requires 2 or more observations.

listing_pr_ppp$n
## [1] 3206
listing_eh_ppp$n
## [1] 3728
listing_sr_ppp$n
## [1] 272
listing_hr_ppp$n
## [1] 507

As there is more than 1 observation for all room types, we proceed with kde analysis.

Compute kde for room type = Private room

Compute kde using automatic badnwidth selection method
kde_listing_pr_bw <- density(listing_pr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 

Convert scale to km to view the labels better

listing_pr_ppp.km <- rescale(listing_pr_ppp, 1000, "km")
kde_listing_pr_bw.km <- density(listing_pr_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 

plot(kde_listing_pr_bw.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_pr_bw <- as.SpatialGridDataFrame.im(kde_listing_pr_bw)
spplot(gridded_kde_listing_pr_bw)

Converting gridded output into raster
kde_listing_pr_bw_raster <- raster(gridded_kde_listing_pr_bw)
kde_listing_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        : NA 
## source     : memory
## names      : v 
## values     : -1.179614e-19, 0.0008332521  (min, max)
Assigning projection systems
projection(kde_listing_pr_bw_raster) <- CRS("+init=EPSG:3414")
kde_listing_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        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -1.179614e-19, 0.0008332521  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_pr_bw_raster) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

As seen above, we can see that Private room room type are mostly concentrated in Chinatown, followed by Lavender, then Bendemeer. There is also a cluster but lesser in areas such as Farrer Park, Aljunied,Tiong Bahru, along River Valley Road, Sophia Road, Victoria street and East Coast Road.

tmap_mode('plot')
## tmap mode set to plotting

Compute kde for room type = Entire house/apt

Compute kde using automatic badnwidth selection method
kde_listing_eh_bw <- density(listing_eh_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 

Convert scale to km to view the labels better

listing_eh_ppp.km <- rescale(listing_eh_ppp, 1000, "km")
kde_listing_eh_bw.km <- density(listing_eh_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 

plot(kde_listing_eh_bw.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_eh_bw <- as.SpatialGridDataFrame.im(kde_listing_eh_bw)
spplot(gridded_kde_listing_eh_bw)

Converting gridded output into raster
kde_listing_eh_bw_raster <- raster(gridded_kde_listing_eh_bw)
kde_listing_eh_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        : NA 
## source     : memory
## names      : v 
## values     : -2.157713e-19, 0.001204593  (min, max)
Assigning projection systems
projection(kde_listing_eh_bw_raster) <- CRS("+init=EPSG:3414")
kde_listing_eh_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        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -2.157713e-19, 0.001204593  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_eh_bw_raster) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

Entire home/apt room type are concentrated in Tanjong Pagar and Geylang. There are also concentrated but less around these 2 areas. Other areas also include along river Valley road, Selegie, Little India, Farrer Park, Potong Pasir and Balestier.

tmap_mode('plot')

Compute kde for room type = Shared room

Compute kde using automatic badnwidth selection method
kde_listing_sr_bw <- density(listing_sr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 

Convert scale to km to view the labels better

listing_sr_ppp.km <- rescale(listing_sr_ppp, 1000, "km")
kde_listing_sr_bw.km <- density(listing_sr_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_sr_bw.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_sr_bw <- as.SpatialGridDataFrame.im(kde_listing_sr_bw)
Converting gridded output into raster
kde_listing_sr_bw_raster <- raster(gridded_kde_listing_sr_bw)
kde_listing_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        : NA 
## source     : memory
## names      : v 
## values     : -2.433489e-20, 0.0001267555  (min, max)
Assigning projection systems
projection(kde_listing_sr_bw_raster) <- CRS("+init=EPSG:3414")
kde_listing_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        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -2.433489e-20, 0.0001267555  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_sr_bw_raster) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

Shared room room type are concentrated aroun Jalan Besar and Bendemeer, along Balestier road and Serangoon road. It is also concentrated in Bugis, along Victoria street and Ophir Road. Other areas aso include Litte India and Bencoolen.

tmap_mode('plot')

Compute kde for room type = Hotel room

Compute kde using automatic badnwidth selection method
kde_listing_hr_bw <- density(listing_hr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 

Convert scale to km to view the labels better

listing_hr_ppp.km <- rescale(listing_hr_ppp, 1000, "km")
kde_listing_hr_bw.km <- density(listing_hr_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_hr_bw.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_hr_bw <- as.SpatialGridDataFrame.im(kde_listing_hr_bw)
Converting gridded output into raster
kde_listing_hr_bw_raster <- raster(gridded_kde_listing_hr_bw)
kde_listing_hr_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        : NA 
## source     : memory
## names      : v 
## values     : -9.344409e-20, 0.000595922  (min, max)
Assigning projection systems
projection(kde_listing_hr_bw_raster) <- CRS("+init=EPSG:3414")
kde_listing_hr_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        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -9.344409e-20, 0.000595922  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_hr_bw_raster) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

Hotel Room are concentrated in Chinatown along Smith Street and Clark Quay along Hongkoong Street.

tmap_mode('plot')

The advantage of kernel density map over point map are thatin kernel density map, we are easily able to identify “hot spots” within a given area. It allows us to see how concentratedan area is, and whther the neghbouring areas display similar results such as a dissipating effect where by as the distance from the most concentrated area increase, the density decreases proportionately as well. Point maps on the other hand enables us to view the exact location. However, we are not able to identify such patterns easily with point maps.

By Planning Subzones

Exploratory Spatial Data Analysis

Extract Airbnb listing by room type within Aljunied, Balestier, Lavender and Tanjong Pagar planning subzones.

aj = mpsz[mpsz@data$SUBZONE_N == "ALJUNIED",]
bl = mpsz[mpsz@data$SUBZONE_N == "BALESTIER",]
lv = mpsz[mpsz@data$SUBZONE_N == "LAVENDER",]
tp = mpsz[mpsz@data$SUBZONE_N == "TANJONG PAGAR",]

Converting the spatial point data frame into generic sp format

Next, we will convert the target areas SpatialPolygonDataFrame into generic spatialpolygons objects

aj_sp = as(aj, "SpatialPolygons")
bl_sp = as(bl, "SpatialPolygons")
lv_sp = as(lv, "SpatialPolygons")
tp_sp = as(tp, "SpatialPolygons")

Convert SpatialPolygons objects into owin objects

aj_owin = as(aj_sp, "owin")
bl_owin = as(bl_sp, "owin")
lv_owin = as(lv_sp, "owin")
tp_owin = as(tp_sp, "owin")
listing_aj_ppp = listing_ppp_jit[aj_owin]
listing_bl_ppp = listing_ppp_jit[bl_owin]
listing_lv_ppp = listing_ppp_jit[lv_owin]
listing_tp_ppp = listing_ppp_jit[tp_owin]

Plot point maps by Subzone

plot(listing_aj_ppp, main="ALJUNIED")

As seen from above, there are alot of listings concentratedin the west and central of Aljunied.

plot(listing_bl_ppp, main="BALESTIER")

There are alot of airbnb listings concentrated in the central and south of Balestier.

plot(listing_lv_ppp, main="LAVENDER")

As seen above, the airbnb listings are almost evenly spread out in Lavender with an exclusion of the south of Lavender.

plot(listing_tp_ppp, main="TANJONG PAGAR")

As compared to the other 3 room types, we can see that there are generally less airbnb listings in Tanjong pagar as compared to the other 3. There are mostly concentrated in the southwest of tanjong pagar.

Peform second order anaysis With reference to the spatial point patterns observed

Analysing Spatial Point Process Using F-Function

The F function estimates the empty space function F(r) or its hazard rate h(r) from a point pattern in a window of arbitrary shape. In this section, you will learn how to compute F-function estimation by using Fest() of spatstat package. You will also learn how to perform monta carlo simulation test using envelope() of spatstat package.

Aljunied planning subzone

Ho = The distribution of airbnb listings in Aljunied are randomly distributed.
H1= The distribution of airbnb listings in Aljunied are not randomly distributed.

Confidence interval: 99.9% (1000 simulations being run)

F_aj.csr <- envelope(listing_aj_ppp, Fest, correction = "all", nsim = 999)
## Generating 999 simulations of CSR  ...
## 1, 2, 3, ......10.........20.........30.........40.........50.........60...
## ......70.........80.........90.........100.........110.........120......
## ...130.........140.........150.........160.........170.........180.........
## 190.........200.........210.........220.........230.........240.........250..
## .......260.........270.........280.........290.........300.........310.....
## ....320.........330.........340.........350.........360.........370........
## .380.........390.........400.........410.........420.........430.........440.
## ........450.........460.........470.........480.........490.........500....
## .....510.........520.........530.........540.........550.........560.......
## ..570.........580.........590.........600.........610.........620.........630
## .........640.........650.........660.........670.........680.........690...
## ......700.........710.........720.........730.........740.........750......
## ...760.........770.........780.........790.........800.........810.........
## 820.........830.........840.........850.........860.........870.........880..
## .......890.........900.........910.........920.........930.........940.....
## ....950.........960.........970.........980.........990........ 999.
## 
## Done.
plot(F_aj.csr)

As seen above, the observed data (blackline) is below the theoretical lin (red line) and is outside of the envelope from around r=11.5. As F lies outside of the envelope at r=11.5 onwards, this suggests that the point pattern is not consistent with the null hypothesis and thus, we reject the null hypothesis at r=11.5 at the significance level of 0.001. Hence, we conclude that the airbnb listings in Aljunied are not randomly distributed in Aljunied and have a clustered pattern.

Balestier planning subzone

Ho = The distribution of airbnb listings in Balestier are randomly distributed.
H1= The distribution of airbnb listings in Balestier are not randomly distributed.

Confidence interval: 99.9% (1000 simulations being run)

F_bl.csr <- envelope(listing_bl_ppp, Fest, correction = "all", nsim = 999)
## Generating 999 simulations of CSR  ...
## 1, 2, 3, ......10.........20.........30.........40.........50.........60...
## ......70.........80.........90.........100.........110.........120......
## ...130.........140.........150.........160.........170.........180.........
## 190.........200.........210.........220.........230.........240.........250..
## .......260.........270.........280.........290.........300.........310.....
## ....320.........330.........340.........350.........360.........370........
## .380.........390.........400.........410.........420.........430.........440.
## ........450.........460.........470.........480.........490.........500....
## .....510.........520.........530.........540.........550.........560.......
## ..570.........580.........590.........600.........610.........620.........630
## .........640.........650.........660.........670.........680.........690...
## ......700.........710.........720.........730.........740.........750......
## ...760.........770.........780.........790.........800.........810.........
## 820.........830.........840.........850.........860.........870.........880..
## .......890.........900.........910.........920.........930.........940.....
## ....950.........960.........970.........980.........990........ 999.
## 
## Done.
plot(F_bl.csr)

As seen above, the observed data (blackline) is below the theoretical lin (red line) and is outside of the envelope from around r=15.6. As F lies outside of the envelope at r=15.6. onwards, this suggests that the point pattern is not consistent with the null hypothesis and thus, we reject the null hypothesis at r=15.6. at the significance level of 0.001. Hence, we conclude that the airbnb listings in Balestier are not randomly distributed in Balestier and have a clustered pattern.

Lavender planning subzone

Ho = The distribution of airbnb listings in Lavender are randomly distributed.
H1= The distribution of airbnb listings in Lavender are not randomly distributed.

Confidence interval: 99.9% (1000 simulations being run)

F_lv.csr <- envelope(listing_lv_ppp, Fest, correction = "all", nsim = 999)
## Generating 999 simulations of CSR  ...
## 1, 2, 3, ......10.........20.........30.........40.........50.........60...
## ......70.........80.........90.........100.........110.........120......
## ...130.........140.........150.........160.........170.........180.........
## 190.........200.........210.........220.........230.........240.........250..
## .......260.........270.........280.........290.........300.........310.....
## ....320.........330.........340.........350.........360.........370........
## .380.........390.........400.........410.........420.........430.........440.
## ........450.........460.........470.........480.........490.........500....
## .....510.........520.........530.........540.........550.........560.......
## ..570.........580.........590.........600.........610.........620.........630
## .........640.........650.........660.........670.........680.........690...
## ......700.........710.........720.........730.........740.........750......
## ...760.........770.........780.........790.........800.........810.........
## 820.........830.........840.........850.........860.........870.........880..
## .......890.........900.........910.........920.........930.........940.....
## ....950.........960.........970.........980.........990........ 999.
## 
## Done.
plot(F_lv.csr)

As seen above, the observed data (blackline) is below the theoretical lin (red line) and is outside of the envelope from around r=13.02. As F lies outside of the envelope at r=13.02 onwards, this suggests that the point pattern is not consistent with the null hypothesis and thus, we reject the null hypothesis at r=13.02 at the significance level of 0.001. Hence, we conclude that the airbnb listings are not randomly distributed in Lavender and have a clustered pattern.

Tanjong Pagar planning subzone

Ho = The distribution of airbnb listings in Tanjong Pagar planning are randomly distributed.
H1= The distribution of airbnb listings in Tanjong Pagar planning are not randomly distributed.

Confidence interval: 99.9% (1000 simulations being run)

F_tp.csr <- envelope(listing_tp_ppp, Fest, correction = "all", nsim = 999)
## Generating 999 simulations of CSR  ...
## 1, 2, 3, ......10.........20.........30.........40.........50.........60...
## ......70.........80.........90.........100.........110.........120......
## ...130.........140.........150.........160.........170.........180.........
## 190.........200.........210.........220.........230.........240.........250..
## .......260.........270.........280.........290.........300.........310.....
## ....320.........330.........340.........350.........360.........370........
## .380.........390.........400.........410.........420.........430.........440.
## ........450.........460.........470.........480.........490.........500....
## .....510.........520.........530.........540.........550.........560.......
## ..570.........580.........590.........600.........610.........620.........630
## .........640.........650.........660.........670.........680.........690...
## ......700.........710.........720.........730.........740.........750......
## ...760.........770.........780.........790.........800.........810.........
## 820.........830.........840.........850.........860.........870.........880..
## .......890.........900.........910.........920.........930.........940.....
## ....950.........960.........970.........980.........990........ 999.
## 
## Done.
plot(F_tp.csr)

As seen above, the observed data (blackline) is below the theoretical lin (red line) and is outside of the envelope from around r=15.97 As F lies outside of the envelope at r=15.97 onwards, this suggests that the point pattern is not consistent with the null hypothesis and thus, we reject the null hypothesis at r=15.97 at the significance level of 0.001. Hence, we conclude that the airbnb listings are not randomly distributed in Tanjong Pagar and have a clustered pattern.

Analysing Spatial Point Process Using L-Function

K-function measures the number of events found up to a given distance of any particular event. IN this case, we are using L-function, which is a the K-function being normalised to obtain a benchmark of zero.

Aljunied planning subzone

Ho = The distribution of airbnb listings in Aljunied are randomly distributed.
H1= The distribution of airbnb listings in Aljunied are not randomly distributed.

Confidence interval: 99.9% (1000 simulations being run)

L_aj = Lest(listing_aj_ppp, correction = "Ripley")
L_aj.csr <- envelope(listing_aj_ppp, Lest, nsim = 999, rank = 1, glocal=TRUE)
## Generating 999 simulations of CSR  ...
## 1, 2, 3, ......10 [etd 19:24] .........20 [etd 19:13] .........
## 30 [etd 19:31] .........40 [etd 20:06] .........50 [etd 19:41] ........
## .60 [etd 19:39] .........70 [etd 19:49] .........80 [etd 19:25] .......
## ..90 [etd 19:27] .........100 [etd 19:30] .........110 [etd 19:22] ......
## ...120 [etd 19:13] .........130 [etd 19:09] .........140 [etd 19:01] .....
## ....150 [etd 19:20] .........160 [etd 19:57] .........170 [etd 20:22] ....
## .....180 [etd 20:27] .........190 [etd 20:36] .........200 [etd 21:01] ...
## ......210 [etd 20:59] .........220 [etd 20:33] .........230 [etd 20:05] ..
## .......240 [etd 19:42] .........250 [etd 19:15] .........260 [etd 18:49] .
## ........270 [etd 18:24] .........280 [etd 18:01] .........290
##  [etd 17:41] .........300 [etd 17:26] .........310 [etd 17:36] .........
## 320 [etd 17:18] .........330 [etd 17:02] .........340 [etd 16:42] ........
## .350 [etd 16:27] .........360 [etd 16:12] .........370 [etd 15:57] .......
## ..380 [etd 15:49] .........390 [etd 15:36] .........400 [etd 15:25] ......
## ...410 [etd 15:11] .........420 [etd 14:57] .........430 [etd 14:44] .....
## ....440 [etd 14:31] .........450 [etd 14:17] .........460 [etd 14:02] ....
## .....470 [etd 13:52] .........480 [etd 13:35] .........490 [etd 13:19] ...
## ......500 [etd 13:03] .........510 [etd 12:47] .........520 [etd 12:32] ..
## .......530 [etd 12:16] .........540 [etd 12:00] .........550 [etd 11:44] .
## ........560 [etd 11:28] .........570 [etd 11:19] .........580
##  [etd 11:05] .........590 [etd 10:49] .........600 [etd 10:34] .........
## 610 [etd 10:17] .........620 [etd 10:00] .........630 [etd 9:43] ........
## .640 [etd 9:27] .........650 [etd 9:10] .........660 [etd 8:53] .......
## ..670 [etd 8:37] .........680 [etd 8:21] .........690 [etd 8:03] ......
## ...700 [etd 7:47] .........710 [etd 7:31] .........720 [etd 7:17] .....
## ....730 [etd 7:03] .........740 [etd 6:48] .........750 [etd 6:33] ....
## .....760 [etd 6:18] .........770 [etd 6:02] .........780 [etd 5:46] ...
## ......790 [etd 5:29] .........800 [etd 5:13] .........810 [etd 4:56] ..
## .......820 [etd 4:40] .........830 [etd 4:23] .........840 [etd 4:07] .
## ........850 [etd 3:52] .........860 [etd 3:36] .........870
##  [etd 3:21] .........880 [etd 3:05] .........890 [etd 2:49] .........
## 900 [etd 2:33] .........910 [etd 2:18] .........920 [etd 2:02] ........
## .930 [etd 1:46] .........940 [etd 1:31] .........950 [etd 1:16] .......
## ..960 [etd 1:00] .........970 [etd 45 sec] .........980 [etd 29 sec] ......
## ...990 [etd 14 sec] ........ 999.
## 
## Done.
title <- "Pairwise Distance: L function"

Laj_df <- as.data.frame(L_aj.csr)

colour=c("#0D657D","#ee770d","#D3D3D3")
Laj_plot <- ggplot(Laj_df, aes(r, obs-r))+
  # plot observed value
  geom_line(colour=c("#4d4d4d"))+
  geom_line(aes(r,theo-r), colour="red", linetype = "dashed")+
  # plot simulation envelopes
  geom_ribbon(aes(ymin=lo-r,ymax=hi-r),alpha=0.1, colour=c("#91bfdb")) +
  xlab("Distance r (km)") +
  ylab("L(r)-r") +
  geom_rug(data=Laj_df[Laj_df$obs > Laj_df$hi,], sides="b", colour=colour[1])  +
  geom_rug(data=Laj_df[Laj_df$obs < Laj_df$lo,], sides="b", colour=colour[2]) +
  geom_rug(data=Laj_df[Laj_df$obs >= Laj_df$lo & Laj_df$obs <= Laj_df$hi,], sides="b", color=colour[3]) +
  theme_tufte()+
  ggtitle(title)

text1<-"Significant clustering"
text2<-"Significant segregation"
text3<-"Not significant clustering/segregation"

# the below conditional statement is required to ensure that the labels (text1/2/3) are assigned to the correct traces
if (nrow(Laj_df[Laj_df$obs > Laj_df$hi,])==0){ 
  if (nrow(Laj_df[Laj_df$obs < Laj_df$lo,])==0){ 
    ggplotly(Laj_plot, dynamicTicks=T) %>%
      style(text = text3, traces = 4) %>%
      rangeslider() 
  }else if (nrow(Laj_df[Laj_df$obs >= Laj_df$lo & Laj_df$obs <= Laj_df$hi,])==0){ 
    ggplotly(Laj_plot, dynamicTicks=T) %>%
      style(text = text2, traces = 4) %>%
      rangeslider() 
  }else {
    ggplotly(Laj_plot, dynamicTicks=T) %>%
      style(text = text2, traces = 4) %>%
      style(text = text3, traces = 5) %>%
      rangeslider() 
  }
} else if (nrow(Laj_df[Laj_df$obs < Laj_df$lo,])==0){
  if (nrow(Laj_df[Laj_df$obs >= Laj_df$lo & Laj_df$obs <= Laj_df$hi,])==0){
    ggplotly(Laj_plot, dynamicTicks=T) %>%
      style(text = text1, traces = 4) %>%
      rangeslider() 
  } else{
    ggplotly(Laj_plot, dynamicTicks=T) %>%
      style(text = text1, traces = 4) %>%
      style(text = text3, traces = 5) %>%
      rangeslider()
  }
} else{
  ggplotly(Laj_plot, dynamicTicks=T) %>%
    style(text = text1, traces = 4) %>%
    style(text = text2, traces = 5) %>%
    style(text = text3, traces = 6) %>%
    rangeslider()
}

The grey area represents the envelope, the red line represents the theoretical line, black line is the observed values after minuing the r. As we can see, the black line (observed values) are above the 0 mark and the black line is above the red line and outside of the envelope, it indicates that it is statistically significant throughout. This can also be seen from the dark green lines, which the entire bar is filled with dark green lines.

As L lies outside of the envelope at r=2.88 onwards, this suggests that the point pattern is not consistent with the null hypothesis and thus, we reject the null hypothesis at r=2.88 at the significance level of 0.001. Hence, we conclude that the airbnb listings are not randomly distributed in Aljunied.

Balestier planning subzone

Ho = The distribution of airbnb listings in Balestier are randomly distributed.
H1= The distribution of airbnb listings in Balestier are not randomly distributed.

Confidence interval: 99.9% (1000 simulations being run)

L_bl = Lest(listing_bl_ppp, correction = "Ripley")
L_bl.csr <- envelope(listing_bl_ppp, Lest, nsim = 999, rank = 1, glocal=TRUE)
## Generating 999 simulations of CSR  ...
## 1, 2, 3, ......10 [etd 3:55] .........20 [etd 4:21] .........
## 30 [etd 4:36] .........40 [etd 4:29] .........50 [etd 4:32] ........
## .60 [etd 4:25] .........70 [etd 4:22] .........80 [etd 4:21] .......
## ..90 [etd 4:19] .........100 [etd 4:23] .........110 [etd 4:33] ......
## ...120 [etd 4:53] .........130 [etd 4:55] .........140 [etd 4:47] .....
## ....150 [etd 4:39] .........160 [etd 4:31] .........170 [etd 4:23] ....
## .....180 [etd 4:17] .........190 [etd 4:16] .........200 [etd 4:10] ...
## ......210 [etd 4:05] .........220 [etd 4:04] .........230 [etd 4:06] ..
## .......240 [etd 4:05] .........250 [etd 4:00] .........260 [etd 3:55] .
## ........270 [etd 3:53] .........280 [etd 3:49] .........290
##  [etd 3:43] .........300 [etd 3:39] .........310 [etd 3:34] .........
## 320 [etd 3:29] .........330 [etd 3:24] .........340 [etd 3:20] ........
## .350 [etd 3:17] .........360 [etd 3:12] .........370 [etd 3:08] .......
## ..380 [etd 3:05] .........390 [etd 3:01] .........400 [etd 2:58] ......
## ...410 [etd 2:54] .........420 [etd 2:50] .........430 [etd 2:46] .....
## ....440 [etd 2:43] .........450 [etd 2:39] .........460 [etd 2:36] ....
## .....470 [etd 2:33] .........480 [etd 2:33] .........490 [etd 2:30] ...
## ......500 [etd 2:27] .........510 [etd 2:24] .........520 [etd 2:21] ..
## .......530 [etd 2:17] .........540 [etd 2:14] .........550 [etd 2:11] .
## ........560 [etd 2:08] .........570 [etd 2:05] .........580
##  [etd 2:02] .........590 [etd 1:59] .........600 [etd 1:56] .........
## 610 [etd 1:53] .........620 [etd 1:50] .........630 [etd 1:47] ........
## .640 [etd 1:44] .........650 [etd 1:41] .........660 [etd 1:38] .......
## ..670 [etd 1:35] .........680 [etd 1:32] .........690 [etd 1:29] ......
## ...700 [etd 1:26] .........710 [etd 1:23] .........720 [etd 1:20] .....
## ....730 [etd 1:17] .........740 [etd 1:14] .........750 [etd 1:11] ....
## .....760 [etd 1:08] .........770 [etd 1:05] .........780 [etd 1:02] ...
## ......790 [etd 59 sec] .........800 [etd 56 sec] .........810 [etd 53 sec] ..
## .......820 [etd 50 sec] .........830 [etd 47 sec] .........840 [etd 45 sec] .
## ........850 [etd 42 sec] .........860 [etd 39 sec] .........870
##  [etd 36 sec] .........880 [etd 34 sec] .........890 [etd 31 sec] .........
## 900 [etd 28 sec] .........910 [etd 25 sec] .........920 [etd 22 sec] ........
## .930 [etd 20 sec] .........940 [etd 17 sec] .........950 [etd 14 sec] .......
## ..960 [etd 11 sec] .........970 [etd 8 sec] .........980 [etd 5 sec] ......
## ...990 [etd 3 sec] ........ 999.
## 
## Done.
title <- "Pairwise Distance: L function"

Lbl_df <- as.data.frame(L_bl.csr)

colour=c("#0D657D","#ee770d","#D3D3D3")
Lbl_plot <- ggplot(Lbl_df, aes(r, obs-r))+
  # plot observed value
  geom_line(colour=c("#4d4d4d"))+
  geom_line(aes(r,theo-r), colour="red", linetype = "dashed")+
  # plot simulation envelopes
  geom_ribbon(aes(ymin=lo-r,ymax=hi-r),alpha=0.1, colour=c("#91bfdb")) +
  xlab("Distance r (km)") +
  ylab("L(r)-r") +
  geom_rug(data=Lbl_df[Lbl_df$obs > Lbl_df$hi,], sides="b", colour=colour[1])  +
  geom_rug(data=Lbl_df[Lbl_df$obs < Lbl_df$lo,], sides="b", colour=colour[2]) +
  geom_rug(data=Lbl_df[Lbl_df$obs >= Lbl_df$lo & Lbl_df$obs <= Lbl_df$hi,], sides="b", color=colour[3]) +
  theme_tufte()+
  ggtitle(title)

text1<-"Significant clustering"
text2<-"Significant segregation"
text3<-"Not significant clustering/segregation"

# the below conditional statement is required to ensure that the labels (text1/2/3) are assigned to the correct traces
if (nrow(Lbl_df[Lbl_df$obs > Lbl_df$hi,])==0){ 
  if (nrow(Lbl_df[Lbl_df$obs < Lbl_df$lo,])==0){ 
    ggplotly(Lbl_plot, dynamicTicks=T) %>%
      style(text = text3, traces = 4) %>%
      rangeslider() 
  }else if (nrow(Lbl_df[Lbl_df$obs >= Lbl_df$lo & Lbl_df$obs <= Lbl_df$hi,])==0){ 
    ggplotly(Lbl_plot, dynamicTicks=T) %>%
      style(text = text2, traces = 4) %>%
      rangeslider() 
  }else {
    ggplotly(Lbl_plot, dynamicTicks=T) %>%
      style(text = text2, traces = 4) %>%
      style(text = text3, traces = 5) %>%
      rangeslider() 
  }
} else if (nrow(Lbl_df[Lbl_df$obs < Lbl_df$lo,])==0){
  if (nrow(Lbl_df[Lbl_df$obs >= Lbl_df$lo & Lbl_df$obs <= Lbl_df$hi,])==0){
    ggplotly(Lbl_plot, dynamicTicks=T) %>%
      style(text = text1, traces = 4) %>%
      rangeslider() 
  } else{
    ggplotly(Lbl_plot, dynamicTicks=T) %>%
      style(text = text1, traces = 4) %>%
      style(text = text3, traces = 5) %>%
      rangeslider()
  }
} else{
  ggplotly(Lbl_plot, dynamicTicks=T) %>%
    style(text = text1, traces = 4) %>%
    style(text = text2, traces = 5) %>%
    style(text = text3, traces = 6) %>%
    rangeslider()
}

The grey area represents the envelope, the red line represents the theoretical line, black line is the observed values after minuing the r. As we can see, the black line (observed values) are above the 0 mark and the black line is above the red line and outside of the envelope, it indicates that it is statistically significant throughout. This can also be seen from the dark green lines, which the entire bar is filled with dark green lines from r=6.5.

As L lies outside of the envelope at r=6.55 onwards, this suggests that the point pattern is not consistent with the null hypothesis and thus, we reject the null hypothesis at r=6.55 at the significance level of 0.001. Hence, we conclude that the airbnb listings are not randomly distributed in Balestier.

Lavender planning subzone

Ho = The distribution of airbnb listings in Lavender are randomly distributed.
H1= The distribution of airbnb listings in Lavender are not randomly distributed.

Confidence interval: 99.9% (1000 simulations being run)

L_lv = Lest(listing_lv_ppp, correction = "Ripley")
plot(L_lv, . -r ~ r, 
     ylab= "L(d)-r", xlab = "d(m)")

L_lv.csr <- envelope(listing_lv_ppp, Lest, nsim = 999, rank = 1, glocal=TRUE)
## Generating 999 simulations of CSR  ...
## 1, 2, 3, ......10 [etd 11:32] .........20 [etd 9:38] .........
## 30 [etd 9:03] .........40 [etd 8:39] .........50 [etd 8:18] ........
## .60 [etd 8:07] .........70 [etd 8:24] .........80 [etd 8:12] .......
## ..90 [etd 7:59] .........100 [etd 8:05] .........110 [etd 8:04] ......
## ...120 [etd 7:57] .........130 [etd 7:49] .........140 [etd 7:41] .....
## ....150 [etd 7:32] .........160 [etd 7:26] .........170 [etd 7:18] ....
## .....180 [etd 7:11] .........190 [etd 7:03] .........200 [etd 6:59] ...
## ......210 [etd 6:52] .........220 [etd 6:45] .........230 [etd 6:38] ..
## .......240 [etd 6:32] .........250 [etd 6:26] .........260 [etd 6:19] .
## ........270 [etd 6:12] .........280 [etd 6:06] .........290
##  [etd 6:00] .........300 [etd 5:54] .........310 [etd 5:48] .........
## 320 [etd 5:43] .........330 [etd 5:38] .........340 [etd 5:32] ........
## .350 [etd 5:26] .........360 [etd 5:21] .........370 [etd 5:15] .......
## ..380 [etd 5:10] .........390 [etd 5:05] .........400 [etd 4:59] ......
## ...410 [etd 4:54] .........420 [etd 4:48] .........430 [etd 4:43] .....
## ....440 [etd 4:37] .........450 [etd 4:33] .........460 [etd 4:27] ....
## .....470 [etd 4:23] .........480 [etd 4:18] .........490 [etd 4:12] ...
## ......500 [etd 4:07] .........510 [etd 4:03] .........520 [etd 3:58] ..
## .......530 [etd 3:54] .........540 [etd 3:49] .........550 [etd 3:44] .
## ........560 [etd 3:39] .........570 [etd 3:34] .........580
##  [etd 3:29] .........590 [etd 3:24] .........600 [etd 3:19] .........
## 610 [etd 3:14] .........620 [etd 3:09] .........630 [etd 3:04] ........
## .640 [etd 3:00] .........650 [etd 2:55] .........660 [etd 2:50] .......
## ..670 [etd 2:46] .........680 [etd 2:41] .........690 [etd 2:36] ......
## ...700 [etd 2:31] .........710 [etd 2:26] .........720 [etd 2:21] .....
## ....730 [etd 2:16] .........740 [etd 2:11] .........750 [etd 2:06] ....
## .....760 [etd 2:01] .........770 [etd 1:56] .........780 [etd 1:51] ...
## ......790 [etd 1:46] .........800 [etd 1:41] .........810 [etd 1:36] ..
## .......820 [etd 1:31] .........830 [etd 1:26] .........840 [etd 1:21] .
## ........850 [etd 1:15] .........860 [etd 1:10] .........870
##  [etd 1:05] .........880 [etd 1:00] .........890 [etd 55 sec] .........
## 900 [etd 50 sec] .........910 [etd 45 sec] .........920 [etd 40 sec] ........
## .930 [etd 35 sec] .........940 [etd 30 sec] .........950 [etd 25 sec] .......
## ..960 [etd 20 sec] .........970 [etd 15 sec] .........980 [etd 10 sec] ......
## ...990 [etd 5 sec] ........ 999.
## 
## Done.
plot(L_lv.csr, . - r ~ r, xlab="d", ylab="L(d)-r")

title <- "Pairwise Distance: L function"

Llv_df <- as.data.frame(L_lv.csr)

colour=c("#0D657D","#ee770d","#D3D3D3")
Llv_plot <- ggplot(Llv_df, aes(r, obs-r))+
  # plot observed value
  geom_line(colour=c("#4d4d4d"))+
  geom_line(aes(r,theo-r), colour="red", linetype = "dashed")+
  # plot simulation envelopes
  geom_ribbon(aes(ymin=lo-r,ymax=hi-r),alpha=0.1, colour=c("#91bfdb")) +
  xlab("Distance r (km)") +
  ylab("L(r)-r") +
  geom_rug(data=Llv_df[Llv_df$obs > Llv_df$hi,], sides="b", colour=colour[1])  +
  geom_rug(data=Llv_df[Llv_df$obs < Llv_df$lo,], sides="b", colour=colour[2]) +
  geom_rug(data=Llv_df[Llv_df$obs >= Llv_df$lo & Llv_df$obs <= Llv_df$hi,], sides="b", color=colour[3]) +
  theme_tufte()+
  ggtitle(title)

text1<-"Significant clustering"
text2<-"Significant segregation"
text3<-"Not significant clustering/segregation"

# the below conditional statement is required to ensure that the labels (text1/2/3) are assigned to the correct traces
if (nrow(Llv_df[Llv_df$obs > Llv_df$hi,])==0){ 
  if (nrow(Llv_df[Llv_df$obs < Llv_df$lo,])==0){ 
    ggplotly(Llv_plot, dynamicTicks=T) %>%
      style(text = text3, traces = 4) %>%
      rangeslider() 
  }else if (nrow(Llv_df[Llv_df$obs >= Llv_df$lo & Llv_df$obs <= Llv_df$hi,])==0){ 
    ggplotly(Llv_plot, dynamicTicks=T) %>%
      style(text = text2, traces = 4) %>%
      rangeslider() 
  }else {
    ggplotly(Llv_plot, dynamicTicks=T) %>%
      style(text = text2, traces = 4) %>%
      style(text = text3, traces = 5) %>%
      rangeslider() 
  }
} else if (nrow(Llv_df[Llv_df$obs < Llv_df$lo,])==0){
  if (nrow(Llv_df[Llv_df$obs >= Llv_df$lo & Llv_df$obs <= Llv_df$hi,])==0){
    ggplotly(Llv_plot, dynamicTicks=T) %>%
      style(text = text1, traces = 4) %>%
      rangeslider() 
  } else{
    ggplotly(Llv_plot, dynamicTicks=T) %>%
      style(text = text1, traces = 4) %>%
      style(text = text3, traces = 5) %>%
      rangeslider()
  }
} else{
  ggplotly(Llv_plot, dynamicTicks=T) %>%
    style(text = text1, traces = 4) %>%
    style(text = text2, traces = 5) %>%
    style(text = text3, traces = 6) %>%
    rangeslider()
}

The grey area represents the envelope, the red line represents the theoretical line, black line is the observed values after minuing the r. As we can see, the black line (observed values) are above the 0 mark and the black line is above the red line and outside of the envelope, it indicates that it is statistically significant throughout. This can also be seen from the dark green lines, which almost the entire bar is filled with dark green lines from r=4.88.

As L lies outside of the envelope at r=6.55 onwards, this suggests that the point pattern is not consistent with the null hypothesis and thus, we reject the null hypothesis at r=4.88 at the significance level of 0.001. Hence, we conclude that the airbnb listings are not randomly distributed in Lavender.

Tanjong Pagar planning subzone

Ho = The distribution of airbnb listings in Tanjong Pagar are randomly distributed.
H1= The distribution of airbnb listings in Tanjong Pagar are not randomly distributed.

Confidence interval: 99.9% (1000 simulations being run)

L_tp = Lest(listing_tp_ppp, correction = "Ripley")
plot(L_tp, . -r ~ r, 
     ylab= "L(d)-r", xlab = "d(m)")

L_tp.csr <- envelope(listing_tp_ppp, Lest, nsim = 999, rank = 1, glocal=TRUE)
## Generating 999 simulations of CSR  ...
## 1, 2, 3, ......10.........20.........30.........40.........50.........60...
## ......70.........80.........90.........100.........110.........120......
## ...130.........140.........150.........160.........170.........180.........
## 190.........200.........210.........220.........230.........240.........250..
## .......260.........270.........280.........290.........300.........310.....
## ....320.........330.........340.........350.........360.........370........
## .380.........390.........400.........410.........420.........430.........440.
## ........450.........460.........470.........480.........490.........500....
## .....510.........520.........530.........540.........550.........560.......
## ..570.........580.........590.........600.........610.........620.........630
## .........640.........650.........660.........670.........680.........690...
## ......700.........710.........720.........730.........740.........750......
## ...760.........770.........780.........790.........800.........810.........
## 820.........830.........840.........850.........860.........870.........880..
## .......890.........900.........910.........920.........930.........940.....
## ....950.........960.........970.........980.........990........ 999.
## 
## Done.
plot(L_tp.csr, . - r ~ r, xlab="d", ylab="L(d)-r")

title <- "Pairwise Distance: L function"

Ltp_df <- as.data.frame(L_tp.csr)

colour=c("#0D657D","#ee770d","#D3D3D3")
Ltp_plot <- ggplot(Ltp_df, aes(r, obs-r))+
  # plot observed value
  geom_line(colour=c("#4d4d4d"))+
  geom_line(aes(r,theo-r), colour="red", linetype = "dashed")+
  # plot simulation envelopes
  geom_ribbon(aes(ymin=lo-r,ymax=hi-r),alpha=0.1, colour=c("#91bfdb")) +
  xlab("Distance r (km)") +
  ylab("L(r)-r") +
  geom_rug(data=Ltp_df[Ltp_df$obs > Ltp_df$hi,], sides="b", colour=colour[1])  +
  geom_rug(data=Ltp_df[Ltp_df$obs < Ltp_df$lo,], sides="b", colour=colour[2]) +
  geom_rug(data=Ltp_df[Ltp_df$obs >= Ltp_df$lo & Ltp_df$obs <= Ltp_df$hi,], sides="b", color=colour[3]) +
  theme_tufte()+
  ggtitle(title)

text1<-"Significant clustering"
text2<-"Significant segregation"
text3<-"Not significant clustering/segregation"

# the below conditional statement is required to ensure that the labels (text1/2/3) are assigned to the correct traces
if (nrow(Ltp_df[Ltp_df$obs > Ltp_df$hi,])==0){ 
  if (nrow(Ltp_df[Ltp_df$obs < Ltp_df$lo,])==0){ 
    ggplotly(Ltp_plot, dynamicTicks=T) %>%
      style(text = text3, traces = 4) %>%
      rangeslider() 
  }else if (nrow(Ltp_df[Laj_df$obs >= Ltp_df$lo & Ltp_df$obs <= Ltp_df$hi,])==0){ 
    ggplotly(Ltp_plot, dynamicTicks=T) %>%
      style(text = text2, traces = 4) %>%
      rangeslider() 
  }else {
    ggplotly(Ltp_plot, dynamicTicks=T) %>%
      style(text = text2, traces = 4) %>%
      style(text = text3, traces = 5) %>%
      rangeslider() 
  }
} else if (nrow(Ltp_df[Ltp_df$obs < Ltp_df$lo,])==0){
  if (nrow(Ltp_df[Ltp_df$obs >= Ltp_df$lo & Ltp_df$obs <= Ltp_df$hi,])==0){
    ggplotly(Ltp_plot, dynamicTicks=T) %>%
      style(text = text1, traces = 4) %>%
      rangeslider() 
  } else{
    ggplotly(Ltp_plot, dynamicTicks=T) %>%
      style(text = text1, traces = 4) %>%
      style(text = text3, traces = 5) %>%
      rangeslider()
  }
} else{
  ggplotly(Ltp_plot, dynamicTicks=T) %>%
    style(text = text1, traces = 4) %>%
    style(text = text2, traces = 5) %>%
    style(text = text3, traces = 6) %>%
    rangeslider()
}

The grey area represents the envelope, the red line represents the theoretical line, black line is the observed values after minuing the r. As we can see, the black line (observed values) are above the 0 mark and the black line is above the red line and outside of the envelope, it indicates that it is statistically significant throughout. This can also be seen from the dark green lines, which almost the entire bar is filled with dark green lines from r=5.87.

As L lies outside of the envelope at r=6.55 onwards, this suggests that the point pattern is not consistent with the null hypothesis and thus, we reject the null hypothesis at r=5.87 at the significance level of 0.001. Hence, we conclude that the airbnb listings are not randomly distributed in Lavender.

kernel density maps by areas and room_types

Kernel Density Estimation in Aljunied

KDE of all room types in Aljunied

kde_listing_aj_ppp<- density(listing_aj_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")
plot(kde_listing_aj_ppp)

Compute kde for room type = Private Room

Filter room type = Private room

listing_aj_pr_ppp <- subset(listing_aj_ppp, marks == "Private room") 
listing_aj_pr_ppp$n
## [1] 226

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_aj_pr_ppp<- density(listing_aj_pr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_aj_pr_ppp.km <- rescale(listing_aj_pr_ppp, 1000, "km")
kde_listing_aj_pr_ppp.km <- density(listing_aj_pr_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_aj_pr_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_aj_pr_ppp<- as.SpatialGridDataFrame.im(kde_listing_aj_pr_ppp)
Converting gridded output into raster
kde_listing_aj_pr_ppp<- raster(gridded_kde_listing_aj_pr_ppp)
kde_listing_aj_pr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 15.34011, 15.85319  (x, y)
## extent     : 32605.74, 34569.28, 31880.27, 33909.48  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : -3.958934e-19, 0.009020694  (min, max)
Assigning projection systems
projection(kde_listing_aj_pr_ppp) <- CRS("+init=EPSG:3414")
kde_listing_aj_pr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 15.34011, 15.85319  (x, y)
## extent     : 32605.74, 34569.28, 31880.27, 33909.48  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -3.958934e-19, 0.009020694  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_aj_pr_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Private rooms in Aljunied, it is concentrated at the junction of Sims AVenue and Aljunied road, along Lorong 23 Geylang.

tmap_mode('plot')

Compute kde for room type = Entire House/apt

Filter room type = Entire House/apt

listing_aj_eh_ppp <- subset(listing_aj_ppp, marks == "Entire home/apt") 
listing_aj_eh_ppp$n
## [1] 580

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_aj_eh_ppp<- density(listing_aj_eh_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_aj_eh_ppp.km <- rescale(listing_aj_eh_ppp, 1000, "km")
kde_listing_aj_eh_ppp.km <- density(listing_aj_eh_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_aj_eh_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_aj_eh_ppp<- as.SpatialGridDataFrame.im(kde_listing_aj_eh_ppp)
Converting gridded output into raster
kde_listing_aj_eh_ppp <- raster(gridded_kde_listing_aj_eh_ppp)
kde_listing_aj_eh_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 15.34011, 15.85319  (x, y)
## extent     : 32605.74, 34569.28, 31880.27, 33909.48  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : -2.99595e-19, 0.003193861  (min, max)
Assigning projection systems
projection(kde_listing_aj_eh_ppp) <- CRS("+init=EPSG:3414")
kde_listing_aj_eh_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 15.34011, 15.85319  (x, y)
## extent     : 32605.74, 34569.28, 31880.27, 33909.48  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -2.99595e-19, 0.003193861  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_aj_eh_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Entire home/apt rooms in Aljunied, it is concentrated at Taima road and Sims Way, along Lorong 4, Lorong 6, Lorong 8 and Lorong 10 Geylang.

tmap_mode('plot')

Compute kde for room type = Shared room

Filter room type = Shared room

listing_aj_sr_ppp <- subset(listing_aj_ppp, marks == "Shared room") 
listing_aj_sr_ppp$n
## [1] 10

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_aj_sr_ppp<- density(listing_aj_sr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_aj_sr_ppp.km <- rescale(listing_aj_sr_ppp, 1000, "km")
kde_listing_aj_sr_ppp.km <- density(listing_aj_sr_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_aj_sr_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_aj_sr_ppp<- as.SpatialGridDataFrame.im(kde_listing_aj_sr_ppp)
Converting gridded output into raster
kde_listing_aj_sr_ppp <- raster(gridded_kde_listing_aj_sr_ppp)
kde_listing_aj_sr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 15.34011, 15.85319  (x, y)
## extent     : 32605.74, 34569.28, 31880.27, 33909.48  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : -1.544588e-21, 2.961817e-05  (min, max)
Assigning projection systems
projection(kde_listing_aj_sr_ppp) <- CRS("+init=EPSG:3414")
kde_listing_aj_sr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 15.34011, 15.85319  (x, y)
## extent     : 32605.74, 34569.28, 31880.27, 33909.48  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -1.544588e-21, 2.961817e-05  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_aj_sr_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Shared rooms in Aljunied, it is highly concentrated at the junction of Sims AVenue along Lorong 27 Geylang, followed by Sims Avenue and along Geylang Road near Grandlink Square. There are also concentrated areas but less in Guillemard Road along Lorong 24A and 26 Geylang, Aljunied road, along Lorong 23 Geylang, Geylang road along Lorong 32 Geylang.

tmap_mode('plot')

Compute kde for room type = Hotel room

Filter room type = Shared room

listing_aj_hr_ppp <- subset(listing_aj_ppp, marks == "Hotel room") 
listing_aj_hr_ppp$n
## [1] 17

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_aj_hr_ppp<- density(listing_aj_hr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_aj_hr_ppp.km <- rescale(listing_aj_sr_ppp, 1000, "km")
kde_listing_aj_hr_ppp.km <- density(listing_aj_hr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_aj_hr_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_aj_hr_ppp<- as.SpatialGridDataFrame.im(kde_listing_aj_hr_ppp)
Converting gridded output into raster
kde_listing_aj_hr_ppp <- raster(gridded_kde_listing_aj_hr_ppp)
kde_listing_aj_hr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 15.34011, 15.85319  (x, y)
## extent     : 32605.74, 34569.28, 31880.27, 33909.48  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : -2.161703e-19, 0.001232471  (min, max)
Assigning projection systems
projection(kde_listing_aj_hr_ppp) <- CRS("+init=EPSG:3414")
kde_listing_aj_hr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 15.34011, 15.85319  (x, y)
## extent     : 32605.74, 34569.28, 31880.27, 33909.48  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -2.161703e-19, 0.001232471  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_aj_hr_ppp) + 
  tm_raster("v", palette = "Greens",alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Hotel rooms in Aljunied, it is highly concentrated at Taima road along Lorong 10 Geylang. There are also concentrated areas but less in Guillemard Road along Lorong 26, Lorong 30 and Lorong 32 Geylang.

tmap_mode('plot')

Kernel Density Estimation in Balestier

KDE of all room types in Balestier

kde_listing_bl_ppp<- density(listing_bl_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")
plot(kde_listing_bl_ppp)

Compute kde for room type = Private Room

listing_bl_pr_ppp <- subset(listing_bl_ppp, marks == "Private room") 
listing_bl_pr_ppp$n
## [1] 60

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_bl_pr_ppp<- density(listing_bl_pr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_bl_pr_ppp.km <- rescale(listing_bl_pr_ppp, 1000, "km")
kde_listing_bl_pr_ppp.km<- density(listing_bl_pr_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_bl_pr_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_bl_pr_ppp<- as.SpatialGridDataFrame.im(kde_listing_bl_pr_ppp)
Converting gridded output into raster
kde_listing_bl_pr_ppp <- raster(gridded_kde_listing_bl_pr_ppp)
kde_listing_bl_pr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 18.93197, 10.39581  (x, y)
## extent     : 28807.86, 31231.15, 33417.93, 34748.59  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : 1.084414e-16, 0.0004129537  (min, max)
Assigning projection systems
projection(kde_listing_bl_pr_ppp) <- CRS("+init=EPSG:3414")
kde_listing_bl_pr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 18.93197, 10.39581  (x, y)
## extent     : 28807.86, 31231.15, 33417.93, 34748.59  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : 1.084414e-16, 0.0004129537  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_bl_pr_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Private rooms in Balestier, it is highly concentrated at Balestier road along Whampoa Drive and Kim Keat Close, and near Balestier Plaza.

tmap_mode('plot')

Compute kde for room type = Entire House/apt

Filter room type = Entire House/apt

listing_bl_eh_ppp <- subset(listing_bl_ppp, marks == "Entire home/apt") 
listing_bl_eh_ppp$n
## [1] 373

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_bl_eh_ppp<- density(listing_bl_eh_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_bl_eh_ppp.km <- rescale(listing_bl_eh_ppp, 1000, "km")
kde_listing_bl_eh_ppp.km<- density(listing_bl_eh_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_bl_eh_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_bl_eh_ppp<- as.SpatialGridDataFrame.im(kde_listing_bl_eh_ppp)
Converting gridded output into raster
kde_listing_bl_eh_ppp <- raster(gridded_kde_listing_bl_eh_ppp)
kde_listing_bl_eh_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 18.93197, 10.39581  (x, y)
## extent     : 28807.86, 31231.15, 33417.93, 34748.59  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : -1.58653e-19, 0.001551059  (min, max)
Assigning projection systems
projection(kde_listing_bl_eh_ppp) <- CRS("+init=EPSG:3414")
kde_listing_bl_eh_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 18.93197, 10.39581  (x, y)
## extent     : 28807.86, 31231.15, 33417.93, 34748.59  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -1.58653e-19, 0.001551059  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_bl_eh_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Entire home/apt rooms in Balestier, it is highly concentrated at Balestier road along Whampoa Drive with many same type listing around the area, followed by at Balestier road along Jalan Rajah and along Ah Hood Road. There are also 2 small concentrated areas with lesser but a few close ones together at Irrawaddy road near Balestier Hill Secondary schoool and another at Jalan Risma Rama.

tmap_mode('plot')

Compute kde for room type = Shared room

Filter room type = Shared room

listing_bl_sr_ppp <- subset(listing_bl_ppp, marks == "Shared room") 
listing_bl_sr_ppp$n
## [1] 1

As there is only 1 shared room in balestier, we are unable to proceed with kde analysis.

Compute kde for room type = Hotel room

Filter room type = Shared room

listing_bl_hr_ppp <- subset(listing_bl_ppp, marks == "Hotel room") 
listing_bl_hr_ppp$n
## [1] 40

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_bl_hr_ppp<- density(listing_bl_hr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_bl_hr_ppp.km <- rescale(listing_bl_hr_ppp, 1000, "km")
kde_listing_bl_hr_ppp.km<- density(listing_bl_hr_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_bl_hr_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_bl_hr_ppp<- as.SpatialGridDataFrame.im(kde_listing_bl_hr_ppp)
Converting gridded output into raster
kde_listing_bl_hr_ppp <- raster(gridded_kde_listing_bl_hr_ppp)
kde_listing_bl_hr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 18.93197, 10.39581  (x, y)
## extent     : 28807.86, 31231.15, 33417.93, 34748.59  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : -2.768176e-20, 0.0002136502  (min, max)
Assigning projection systems
projection(kde_listing_bl_hr_ppp) <- CRS("+init=EPSG:3414")
kde_listing_bl_hr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 18.93197, 10.39581  (x, y)
## extent     : 28807.86, 31231.15, 33417.93, 34748.59  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -2.768176e-20, 0.0002136502  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_bl_hr_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Hotel rooms in Balestier, it is highly concentrated at Balestier road along Pegu Road with many same type listing around the area, followed by along Jalan Rajah and Jalan Rama Rama.

tmap_mode('plot')

Kernel Density Estimation in Lavender

KDE of all room types in Lavender

kde_listing_lv_ppp<- density(listing_lv_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")
plot(kde_listing_lv_ppp)

Compute kde for room type = Private Room

Filter room type = Private room

listing_lv_pr_ppp <- subset(listing_lv_ppp, marks == "Private room") 
listing_lv_pr_ppp$n
## [1] 281

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_lv_pr_ppp<- density(listing_lv_pr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_lv_pr_ppp.km <- rescale(listing_lv_pr_ppp, 1000, "km")
kde_listing_lv_pr_ppp.km<- density(listing_lv_pr_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_lv_pr_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_lv_pr_ppp<- as.SpatialGridDataFrame.im(kde_listing_lv_pr_ppp)
Converting gridded output into raster
kde_listing_lv_pr_ppp <- raster(gridded_kde_listing_lv_pr_ppp)
kde_listing_lv_pr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 8.682154, 9.355564  (x, y)
## extent     : 30342.65, 31453.96, 32035.6, 33233.11  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : -2.989929e-19, 0.006048835  (min, max)
Assigning projection systems
projection(kde_listing_lv_pr_ppp) <- CRS("+init=EPSG:3414")
kde_listing_lv_pr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 8.682154, 9.355564  (x, y)
## extent     : 30342.65, 31453.96, 32035.6, 33233.11  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -2.989929e-19, 0.006048835  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_lv_pr_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Private rooms in Lavender, it is highly concentrated at along Tyrwhitt road and Beauty Lane. There are other areas with less concentrated but has rooms of the same type nearby at Sturdee road at sturdee residents, along King George’s Avenue, Horne road and Cavan road, as well as Sturdee road at Sturdee Residents.

tmap_mode('plot')

Compute kde for room type = Entire House/apt

Filter room type = Entire House/apt

listing_lv_eh_ppp <- subset(listing_lv_ppp, marks == "Entire home/apt") 
listing_lv_eh_ppp$n
## [1] 122

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_lv_eh_ppp<- density(listing_lv_eh_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_lv_eh_ppp.km <- rescale(listing_lv_eh_ppp, 1000, "km")
kde_listing_lv_eh_ppp.km<- density(listing_lv_eh_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_lv_eh_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_lv_eh_ppp<- as.SpatialGridDataFrame.im(kde_listing_lv_eh_ppp)
Converting gridded output into raster
kde_listing_lv_eh_ppp <- raster(gridded_kde_listing_lv_eh_ppp)
kde_listing_lv_eh_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 8.682154, 9.355564  (x, y)
## extent     : 30342.65, 31453.96, 32035.6, 33233.11  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : 5.004017e-16, 0.0007961122  (min, max)
Assigning projection systems
projection(kde_listing_lv_eh_ppp) <- CRS("+init=EPSG:3414")
kde_listing_lv_eh_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 8.682154, 9.355564  (x, y)
## extent     : 30342.65, 31453.96, 32035.6, 33233.11  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : 5.004017e-16, 0.0007961122  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_lv_eh_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Entire home/apt rooms in Lavender, it is highly concentrated at several areas: along Sturdee road, Kitchener Link, Serangoon Road (near Petain Road and Tessensohn road).

tmap_mode('plot')

Compute kde for room type = Shared room

Filter room type = Shared room

listing_lv_sr_ppp <- subset(listing_lv_ppp, marks == "Shared room") 
listing_lv_sr_ppp$n
## [1] 48

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_lv_sr_ppp<- density(listing_lv_sr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_lv_sr_ppp.km <- rescale(listing_lv_sr_ppp, 1000, "km")
kde_listing_lv_sr_ppp.km<- density(listing_lv_sr_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_lv_sr_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_lv_sr_ppp<- as.SpatialGridDataFrame.im(kde_listing_lv_sr_ppp)
Converting gridded output into raster
kde_listing_lv_sr_ppp <- raster(gridded_kde_listing_lv_sr_ppp)
kde_listing_lv_sr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 8.682154, 9.355564  (x, y)
## extent     : 30342.65, 31453.96, 32035.6, 33233.11  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : -2.18318e-19, 0.003690614  (min, max)
Assigning projection systems
projection(kde_listing_lv_sr_ppp) <- CRS("+init=EPSG:3414")
kde_listing_lv_sr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 8.682154, 9.355564  (x, y)
## extent     : 30342.65, 31453.96, 32035.6, 33233.11  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -2.18318e-19, 0.003690614  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_lv_sr_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Shared rooms in Lavender, it is highly concentrated at just one area: Along Jalan Besar road at Streetart road.

tmap_mode('plot')

Compute kde for room type = Hotel room

Filter room type = Shared room

listing_lv_hr_ppp <- subset(listing_lv_ppp, marks == "Hotel room") 
listing_lv_hr_ppp$n
## [1] 42

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_lv_hr_ppp<- density(listing_lv_hr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_lv_hr_ppp.km <- rescale(listing_lv_hr_ppp, 1000, "km")
kde_listing_lv_hr_ppp.km<- density(listing_lv_hr_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_lv_hr_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_lv_hr_ppp<- as.SpatialGridDataFrame.im(kde_listing_lv_hr_ppp)
Converting gridded output into raster
kde_listing_lv_hr_ppp <- raster(gridded_kde_listing_lv_hr_ppp)
kde_listing_lv_hr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 8.682154, 9.355564  (x, y)
## extent     : 30342.65, 31453.96, 32035.6, 33233.11  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : -2.593441e-19, 0.004004417  (min, max)
Assigning projection systems
projection(kde_listing_lv_hr_ppp) <- CRS("+init=EPSG:3414")
kde_listing_lv_hr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 8.682154, 9.355564  (x, y)
## extent     : 30342.65, 31453.96, 32035.6, 33233.11  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -2.593441e-19, 0.004004417  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_lv_hr_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Hotel rooms in Lavender, it is concentrated at only one area: along Serangoong road and Beauty road.

tmap_mode('plot')

Kernel Density Estimation in Tanjong Pagar

KDE of all room types in Tanjong Pagar

kde_listing_tp_ppp<- density(listing_tp_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")
plot(kde_listing_tp_ppp)

Compute kde for room type = Private Room

Filter room type = Private room

listing_tp_pr_ppp <- subset(listing_tp_ppp, marks == "Private room") 
listing_tp_pr_ppp$n
## [1] 20

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_tp_pr_ppp<- density(listing_tp_pr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_tp_pr_ppp.km <- rescale(listing_tp_pr_ppp, 1000, "km")
kde_listing_tp_pr_ppp.km<- density(listing_tp_pr_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_tp_pr_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_tp_pr_ppp<- as.SpatialGridDataFrame.im(kde_listing_tp_pr_ppp)
Converting gridded output into raster
kde_listing_tp_pr_ppp <- raster(gridded_kde_listing_tp_pr_ppp)
kde_listing_tp_pr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 3.758669, 4.986962  (x, y)
## extent     : 29169.13, 29650.24, 28430.25, 29068.58  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : 1.062711e-13, 0.0006217762  (min, max)
Assigning projection systems
projection(kde_listing_tp_pr_ppp) <- CRS("+init=EPSG:3414")
kde_listing_tp_pr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 3.758669, 4.986962  (x, y)
## extent     : 29169.13, 29650.24, 28430.25, 29068.58  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : 1.062711e-13, 0.0006217762  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_tp_pr_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Private rooms in Tanjong Pagar, it is extremely highly concentrated at along Anson road and Parsi Road with many rooms of the same type nearby. There are also other less concentrated areas such as along Wallich Street and Mistri road.

tmap_mode('plot')

Compute kde for room type = Entire House/apt

Filter room type = Entire House/apt

listing_tp_eh_ppp <- subset(listing_tp_ppp, marks == "Entire home/apt") 
listing_tp_eh_ppp$n
## [1] 146

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_tp_eh_ppp<- density(listing_tp_eh_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")

Convert scale to km to view the labels better

listing_tp_eh_ppp.km <- rescale(listing_tp_eh_ppp, 1000, "km")
kde_listing_tp_eh_ppp.km<- density(listing_tp_eh_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_tp_eh_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_tp_eh_ppp<- as.SpatialGridDataFrame.im(kde_listing_tp_eh_ppp)
Converting gridded output into raster
kde_listing_tp_eh_ppp <- raster(gridded_kde_listing_tp_eh_ppp)
kde_listing_tp_eh_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 3.758669, 4.986962  (x, y)
## extent     : 29169.13, 29650.24, 28430.25, 29068.58  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : 3.790235e-19, 0.007177688  (min, max)
Assigning projection systems
projection(kde_listing_tp_eh_ppp) <- CRS("+init=EPSG:3414")
kde_listing_tp_eh_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 3.758669, 4.986962  (x, y)
## extent     : 29169.13, 29650.24, 28430.25, 29068.58  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : 3.790235e-19, 0.007177688  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_tp_eh_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Entire home/apt rooms in Tanjong Pagar, it is extremely highly concentrated at along Anson road and Tras Street with many rooms of the same type nearby.

tmap_mode('plot')

Compute kde for room type = Shared room

Filter room type = Shared room

listing_tp_sr_ppp <- subset(listing_tp_ppp, marks == "Shared room") 
listing_tp_sr_ppp$n
## [1] 0

As seen aboove, there are no shared rooms in Tanjong Pagar, hence we do not proceed with kde analysis.

Compute kde for room type = Hotel room

Filter room type = Shared room

listing_tp_hr_ppp <- subset(listing_tp_ppp, marks == "Hotel room") 
listing_tp_hr_ppp$n
## [1] 2

As there is more than 1 observation, we proceed with kde analysis as it requires more than 1 observation.

kde_listing_tp_hr_ppp<- density(listing_tp_hr_ppp, sigma=bw.diggle, edge=TRUE, kernel="gaussian")
plot(kde_listing_tp_hr_ppp)

Convert scale to km to view the labels better

listing_tp_hr_ppp.km <- rescale(listing_tp_hr_ppp, 1000, "km")
kde_listing_tp_hr_ppp.km<- density(listing_tp_hr_ppp.km, sigma=bw.diggle, edge=TRUE, kernel="gaussian") 
plot(kde_listing_tp_hr_ppp.km)

Converting KDE output into grid object.

The result is the same, we just convert it so that it is suitable for mapping purposes

gridded_kde_listing_tp_hr_ppp<- as.SpatialGridDataFrame.im(kde_listing_tp_hr_ppp)
Converting gridded output into raster
kde_listing_tp_hr_ppp <- raster(gridded_kde_listing_tp_hr_ppp)
kde_listing_tp_hr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 3.758669, 4.986962  (x, y)
## extent     : 29169.13, 29650.24, 28430.25, 29068.58  (xmin, xmax, ymin, ymax)
## crs        : NA 
## source     : memory
## names      : v 
## values     : -1.916235e-20, 0.000177147  (min, max)
Assigning projection systems
projection(kde_listing_tp_hr_ppp) <- CRS("+init=EPSG:3414")
kde_listing_tp_hr_ppp
## class      : RasterLayer 
## dimensions : 128, 128, 16384  (nrow, ncol, ncell)
## resolution : 3.758669, 4.986962  (x, y)
## extent     : 29169.13, 29650.24, 28430.25, 29068.58  (xmin, xmax, ymin, ymax)
## crs        : +init=EPSG:3414 +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs 
## source     : memory
## names      : v 
## values     : -1.916235e-20, 0.000177147  (min, max)
Visualising the output in tmap
tmap_mode("view")
tm_basemap("OpenStreetMap")+
tm_shape(kde_listing_tp_hr_ppp) + 
  tm_raster("v", palette = "Greens", alpha= 0.8) +
  tm_layout(legend.position = c("right", "bottom"), frame = FALSE)

For Hotel rooms in Tanjong Pagar, it is highly concentrated at Anson road along Prince Edward road.

tmap_mode('plot')

Overall, the spatial patterns observed may be due to how near these airbnb listing. As airbnb are commonly used for tourists, tourists may choose to stay in airbnb that are more convenient for them to travel around. Hence due to the demand, there are more listings around centre and south off Singapore that are near tourist/crowd hotspot areas in Singapore. On top of that, for Singaporeans who may want to find an airbnb to stay temporarily, it is most likely due to a short vacation or maybe ther reasons such as moving of house etc. Hence, if they were to find an airbnb to stay in, it is most likely near Town/CBD as it is more convenient for them to go to work. As for those on vacation, it is more convenient for them to access areas of interest such as the tourist attractions areas as well. As for the clustered patterns found in the respective room types, this may be due to the housing types available at each area (e.g. HDB are usually clustered together, private housing are usually clustered together as well.) On top of that, both factors may overlap. For an example, HDB are not allowed to rent out their apartment. Hence, areas which are HDB are most likely rent out to Singaporeans who are probably staying due to the 2 reasons mentioned earlier. Thus, the type of room that they will rent may most likely be similar due to the needs that they have.