Database Queries dan Spatial Data

Koneksi Database

Ada beberapa cara di R untuk mengimpor dari RDMBS. Package yang dapat digunakan untuk fungsi tersebut adalah DBI. DBI A database interface definition for communication between R and relational database management systems. All classes in this package are virtual and need to be extended by the various R/DBMS implementations. Disediakan beberapa fungsi yang diinterpretasikan dengan package lain. Package lain yang berhubungan dengan RDBMS adalah: RODBC, RSQLite, RMySQL, RMariaDB, dll. Untuk dapat melakukan fungsi-fungsi yang ada pada package tersebut maka lakukan instalasi package terlebih dahulu.

Install Package

install.packages("DBI")
install.packages("RODBC")
install.packages("RSQLite")

Connect with RODBC

RODBC merupakan package yang menghubungkan RDBMS dengan aplikasi dengan konektor ODBC. Sebelumnya lakukan konfigurasi terlebih dahulu pada ODBC DSN Configuration dengan beberapa langkah. Tambahkan System DSN dengan menggunakan tombol Add. Setelah itu, pilih SQLite3 ODBC Driver. Kemudian isikan Data Source Name, dan isikan Database Name berikut path database tersebut berada.

Jika sudah, maka library RODBC dapat digunakan.

library(RODBC)

Selanjutnya dapat membuat koneksi ke database dengan menggunakan fungsi odbcConnect. Koneksi tersebut disimpan dalam sebuah objek, sebagai contoh akan disimpan ke dalam objek con.

# koneksi dengan fungsi odbc connect terhadap DSN-nya
# nama DSN yang digunakan tadi adalah "northwind"
con <- odbcConnect("northwind", believeNRows = FALSE, rows_at_time = 1)

Untuk melihat tabel apa saja yang berada di dalam database, dapat menggunakan fungsi sqlTables

# Fungsi untuk me-list table di dalam database
sqlTables(con, "Northwind_large.sqlite")
   TABLE_CAT TABLE_SCHEM           TABLE_NAME TABLE_TYPE REMARKS
1       <NA>        <NA>             Employee      TABLE    <NA>
2       <NA>        <NA>             Category      TABLE    <NA>
3       <NA>        <NA>             Customer      TABLE    <NA>
4       <NA>        <NA>              Shipper      TABLE    <NA>
5       <NA>        <NA>             Supplier      TABLE    <NA>
6       <NA>        <NA>                Order      TABLE    <NA>
7       <NA>        <NA>              Product      TABLE    <NA>
8       <NA>        <NA>          OrderDetail      TABLE    <NA>
9       <NA>        <NA> CustomerCustomerDemo      TABLE    <NA>
10      <NA>        <NA>  CustomerDemographic      TABLE    <NA>
11      <NA>        <NA>               Region      TABLE    <NA>
12      <NA>        <NA>            Territory      TABLE    <NA>
13      <NA>        <NA>    EmployeeTerritory      TABLE    <NA>
14      <NA>        <NA>     ProductDetails_V       VIEW    <NA>

Untuk mematikan koneksi dengan database dapat menggunakan fungsi odbcClose

odbcClose(con)

Connect with RSQLite

Jika RODBC dapat digunakan untuk RDBMS apa saja selama tersedia driver-nya, package RSQLite ini digunakan khusus untuk SQLite.

Menyiapkan Database dengan Menggunakan dbConnect()

Untuk melakukan koneksi ke database, dapat dilakukan dengan beberapa cara. Cara pertama: menggunakan library DBI. Jika menggunakan library DBI, maka ketika membuat koneksi ke database, menggunakan RSQLite::.

library(DBI)
# koneksi ke database, 
mydb <- dbConnect(RSQLite::SQLite(), "D:\\Northwind_large.sqlite")
mydb
<SQLiteConnection>
  Path: D:\Northwind_large.sqlite
  Extensions: TRUE

Untuk mematikan koneksi dengan database dapat menggunakan fungsi dbDisconnect

# mematikan koneksi database
dbDisconnect(mydb)

Cara kedua: menggunakan library RSQLite

library(RSQLite)
# koneksi ke database, 
mydb <- dbConnect(SQLite(), "D:\\Northwind_large.sqlite")
mydb
<SQLiteConnection>
  Path: D:\Northwind_large.sqlite
  Extensions: TRUE

Untuk melihat tabel-tabel di dalam database tersebut dapat menggunakan fungsi dbListTables

dbListTables(mydb)
 [1] "Category"             "Customer"             "CustomerCustomerDemo"
 [4] "CustomerDemographic"  "Employee"             "EmployeeTerritory"   
 [7] "Order"                "OrderDetail"          "Product"             
[10] "ProductDetails_V"     "Region"               "Shipper"             
[13] "Supplier"             "Territory"           

Retrieve Data dengan RODBC

Setelah berhasil melakukan koneksi database dengan R, selanjutnya dapat melakukan retrieve data. Untuk me-retrieve data dapat menggunakan beberapa cara, seperti sqlQuery atau sqlFetch.

Berikut adalah ilustrasi penggunaan sqlQuery dengan menyimpan terlebih dahulu query yang akan digunakan ke dalam sebuah objek.

# SQL untuk meretrieve data dari tabel product disimpan pada objek txtSQL
txtSQL <- "SELECT * FROM Product"
# meretrieve data berdasarkan SQL
mydata <- sqlQuery(con, txtSQL)

Menggunakan sqlFetch untuk mengambil keseluruhan isi tabel. Perlu diperhatikan memory yang ada jika tabel yang akan diambil besar.

# Meretrieve data berdasarkan tabel
mydata <- sqlFetch(con, "Product")

Query dengan Package RSQLite

Jika sudah memiliki data di dalam SQLite, ada beberapa cara untuk retrieve data atau untuk query data, yaitu menggunakan dbGetQuery, Batched Queries, atau melakukan setting pada engine sehingga bisa menggunakan syntax SQL secara langsung.

dbGetQuery()

Fungsi dbGetQQuery memungkinkan kita untuk menuliskan query dan mengambil hasilnya. Query harus dituliskan menggunakan syntax SQL yang sesuai dengan tipe databasenya.

# menyimpan quey pada txtSQL
txtSQL <- "SELECT * FROM Product"

# retrieve data 
mydata <- dbGetQuery(mydb, txtSQL)

Batched queries

Jika data yang akan diambil besar dan memory tidak cukup untuk mengambil data sekaligus, maka pengambilan data dapat dibagi-bagi. Fungsi yang dapat digunakan dalam batched queries adalah dbSendQuery, dbFetch, dbHasCompleted, dbClearResults. Pada dbFetch, default-nya akan mengambil semua data yang ada pada suatu tabel. Hal ini dapat kita atur untuk mengambil sebagian datanya dengan me-setting paramater n-nya. dbHasCompleted akan memeriksa apakah semua data sudah terambil atau belum.

Sebagai ilustrasi, akan diambil data dari tabel Product yang berisi 77 baris, dengan menggunakan fungsi dbFetch dan memberi nilai n=10 pada parameter n-nya, maka yang diambil adalah 10 record saja. Selanjutnya fungsi dbHasCompleted akan memeriksa apakah semua data pada tabel tersebut sudah terambil atau belum.

rs <- dbSendQuery(mydb, txtSQL)

# mengambil data, default mengambil seluruh data, bisa diatur ambil berapa baris
d1 <- dbFetch(rs, n= 10)
# memeriksa apakah semua data sudah terambil atau belum
# bernilai false
dbHasCompleted(rs)
[1] FALSE

dbHasCompleted akan bernilai FALSE karena belum semua data di tabel tersebut terambil. Untuk mengambil sisa data di tabel tersebut, maka parameter n dapat di-setting dengan nilai -1 atau inv.

# mengambil sisanya dengan mengganti n=-1
d2 <- dbFetch(rs, n = -1)

Lakukan pengecekan apakah semua record sudah terambil. Jika sudah maka dbHasCompleted akan bernilai TRUE.

# mengecek apakah sudah selesai
dbHasCompleted(rs)
[1] TRUE

Jika sudah selesai bersihkan dengan dbClearResults.

dbClearResult(rs)

# mematikan koneksi
dbDisconnect(mydb)

SQL Engine

Cara lain untuk dapat menggunakan syntax SQL pada R adalah dengan men-setting koneksi dan engine-nya. Dengan menambahkan parameter connection dan engine="sql".

Selanjutnya jika sudah dilakukan setting, maka syntax SQL dapat langsung diaplikasikan. Sebagai ilustrasi, menggunakan fungsi select.

```{r, connection=mydb, engine="sql"}
SELECT * FROM Product;

Inner Join

Join merupakan sebuah proses untuk menggabungkan tabel. Ada berbagai cara untuk melakukan join yaitu inner join, left join, right join, full join, semi join, anti join, dll. Namun, penggunaan join dalam package RSQLite ini hanya akan dilakukan untuk dua jenis join, yaitu inner join dan left join. Sebagai ilustrasi akan dilakukan join tabel dari database Northwind.

Terdapat tabel Product, Supplier, yang akan digabungkan menjadi satu tabel berisi id, ProductName, CompanyName, dan Address, maka akan digabungkan dengan INNER JOIN. Inner join akan mengembalikan tabel yang mempunyai nilai yang sama pada kedua tabel.

SELECT a.Id, a.ProductName, b.CompanyName, b.Address
  FROM Product as a INNER JOIN Supplier as b
  ON a.SupplierId=b.Id;

Left Join

Misalkan kita ingin melihat informasi mengenai penjelasan kategori untuk masing masing produk, maka dapat dilakukan dengan menggabungkan tabel Products dan Categories menggunakan fungsi LEFT JOIN. Fungsi LEFT JOIN akan mengembalikan semua nilai dari tabel di sebelah kiri (tabel 1) yang mempunyai nilai yang sama dengan tabel di sebelah kanan (tabel 2). Jika di tabel sebelah kanan tidak ada data yang sama, makan akan terisi null.

SELECT a.Id, a.ProductName, b.CategoryName, b.Description
  FROM Product as a LEFT JOIN Category as b
  ON a.CategoryId=b.Id

3a. Join dengan Package dplyr

Package dplyr juga dapat digunakan untuk mengakses tabel pada database dengan menggunakan fungsi tbl(database, "table"). Sebagai ilustrasi, akan digunakan database chinook.db.

library(RSQLite)
library(dplyr)
mydb <- dbConnect(SQLite(), "D:\\chinook.db")
dbListTables(mydb)
 [1] "albums"          "artists"         "customers"       "employees"      
 [5] "genres"          "invoice_items"   "invoices"        "media_types"    
 [9] "playlist_track"  "playlists"       "sqlite_sequence" "sqlite_stat1"   
[13] "tracks"         

Fungsi tbl

Menuliskan fungsi SQL dengan menggunakan fungsi tbl dari package dplyr. Berikut akan diambil beberapa tabel dari database chinook untuk dilakukan proses join. Untuk mengambil tabel tersebut dapat dilakukan dengan fungsi berikut.

tbl.albums <- tbl(mydb, sql("SELECT * FROM albums"))
tbl.playlistTrack <- tbl(mydb, sql("SELECT * FROM playlist_track"))
tbl.playlist <-tbl(mydb,sql("SELECT * FROM playlists"))
tbl.artists <- tbl(mydb, sql("SELECT * FROM artists"))
tbl.genres <- tbl(mydb, sql("SELECT * FROM genres"))
tbl.tracks <- tbl(mydb, sql("SELECT * FROM tracks"))

inner_join

Inner join tabel juga dapat dilakukan dengan package dplyr menggunakan fungsi inner_join. inner_join akan digunakan untuk menggabungkan Tabel Artist dan Album

inner_join(tbl.artists, tbl.albums)
Joining, by = "ArtistId"

Hasil dari inner_join tersebut adalah menampilkan seluruh nilai yang sama dari tabel “Artist” dan “Albums”, serta menampilkan semua kolom pada masing masing tabel.

left_join

Menggunakan left_join untuk menggabungkan tabel “Tracks” dan “Album”.

left_join(tbl.albums, tbl.tracks) 
Joining, by = "AlbumId"

right_join

Fungsi right join akan mengembalikan semua nilai dari tabel di sebelah kanan (tabel 2) yang mempunyai nilai yang sama dengan tabel di sebelah kiri (tabel 1). Nilai yang dikembalikan akan null dari tabel di sebelah kiri jika tidak ada data yang sama. Sebagai ilustrasi akan dilakukan right join dengan menggunakan fungsi right_join pada tabel “Album” dan “Artist”.

right_join(tbl.albums, tbl.artists) 
Joining, by = "ArtistId"

full_join

Full join akan mengembalikan semua nilai yang sama dari tabel di sebelah kiri (tabel 1) atau tabel di sebelah kanan (tabel 2). Full join dapat dilakukan dengan menggunakan fungsi full_join. Sebagai ilustrasi akan dilakukan full join dari tabel “Playlist” dan “Playlist Tracks”

full_join(tbl.playlist, tbl.playlistTrack)
Joining, by = "PlaylistId"

semi_join

Fungsi semi_join akan mengembalikan semua nilai yang sama pada tabel di sebelah kiri (tabel 1) dengan tabel di sebelah kanan (tabel 2), dengan mengembalikan semua kolom dari tabel 1. Ilustrasi yang sama akan digunakan pada fungsi ini adalah menggabungkan tabel Genre dan tabel Track.

trackFilter <- tbl.tracks %>% 
  rename(SongName = Name)
semi_join(tbl.genres, trackFilter)
Joining, by = "GenreId"

anti_join

Fungsi anti_join akan mengembalikan nilai pada tabel di sebelah kiri (tabel 1) yang tidak memiliki nilai yang sama dengan tabel di sebelah kanan (tabel 2), dan menampilkan semua kolom pada tabel 1. Ilustrasi yang sama akan digunakan pada fungsi ini adalah untuk tabel Artist dan Album.

anti_join(tbl.artists, tbl.albums)
Joining, by = "ArtistId"

Data Spasial

Data spasial tidak terdiri dari baris dan kolom, tetapi geometris objek seperti titik, garis, dan poligon. Bentuk file berisi instruksi berbasis vektor biasanya untuk menggambar batas negara, kabupaten, kota, dll. Format yang paling umum digunakan untuk data spasial adalah shapefiles.

Shapefiles

Shapefiles terdiri dari beberapa file dengan beberapa ekstensi yang disimpan dalam satu direktori dengan nama file yang sama. Ekstensi yang membentuk shapefiles adalah .shp, .shx, .dbf. Terdapat beberapa package di R untuk membaca shapefiles, tetapi yang sering digunakan adalah package sp dan rgdal.

Membaca Shapefiles

Untuk membaca shapefiles menggunakan package rgdal maka pertama buat objek berisi path dimana shapefiles tersebut berada. Gunakan perintah list.files(objek) untuk melist semua file di dalam folder yang dituju.

library(rgdal)
# menyimpan path folder ke dsn
dsn <- "D:\\SD\\SnowGIS_SHP"

# menampilkan semua file di folder tersebut
list.files(dsn)
 [1] "Cholera_Deaths.dbf"          "Cholera_Deaths.prj"         
 [3] "Cholera_Deaths.sbn"          "Cholera_Deaths.sbx"         
 [5] "Cholera_Deaths.shp"          "Cholera_Deaths.shx"         
 [7] "OSMap.tfw"                   "OSMap.tif"                  
 [9] "OSMap_Grayscale.tfw"         "OSMap_Grayscale.tif"        
[11] "OSMap_Grayscale.tif.aux.xml" "OSMap_Grayscale.tif.ovr"    
[13] "Pumps.dbf"                   "Pumps.prj"                  
[15] "Pumps.sbx"                   "Pumps.shp"                  
[17] "Pumps.shx"                   "README.txt"                 
[19] "SnowMap.tfw"                 "SnowMap.tif"                
[21] "SnowMap.tif.aux.xml"         "SnowMap.tif.ovr"            

Untuk melihat ada shapefiles apa saja di dalam folder dapat menggunakan fungsi ogrListLayers(objekPath).

# melihat ada berapa shapefiles, dan shapefilesnya apa saja
ogrListLayers(dsn)
[1] "Cholera_Deaths" "Pumps"         
attr(,"driver")
[1] "ESRI Shapefile"
attr(,"nlayers")
[1] 2
# mengetahui informasi tentang shapefiles
ogrInfo(dsn, layer = "Cholera_Deaths")
Source: "D:\SD\SnowGIS_SHP", layer: "Cholera_Deaths"
Driver: ESRI Shapefile; number of rows: 250 
Feature type: wkbPoint with 2 dimensions
Extent: (529160.3 180857.9) - (529655.9 181306.2)
CRS: +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +units=m +no_defs 
LDID: 87 
Number of fields: 2 
   name type length typeName
1    Id    0      6  Integer
2 Count    0      4  Integer

Untuk melihat informasi mengenai suatu shapefiles dapat menggunakan fungsi ogrInfo

ogrInfo(dsn, layer="Cholera_Deaths")
Source: "D:\SD\SnowGIS_SHP", layer: "Cholera_Deaths"
Driver: ESRI Shapefile; number of rows: 250 
Feature type: wkbPoint with 2 dimensions
Extent: (529160.3 180857.9) - (529655.9 181306.2)
CRS: +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +units=m +no_defs 
LDID: 87 
Number of fields: 2 
   name type length typeName
1    Id    0      6  Integer
2 Count    0      4  Integer

Untuk membaca data di dalam shapefiles dapat menggunakan fungsi readOGR.

# Membaca data shapefiles ke dalam objek R hasilnya adalah class khusus objek spasial
CholeraDeaths <- readOGR(dsn, layer = "Cholera_Deaths")
OGR data source with driver: ESRI Shapefile 
Source: "D:\SD\SnowGIS_SHP", layer: "Cholera_Deaths"
with 250 features
It has 2 fields
class(CholeraDeaths)
[1] "SpatialPointsDataFrame"
attr(,"package")
[1] "sp"

Untuk menampilkan statistik yang berada di dalam objek tersebut maka menggunakan fungsi summary

summary(CholeraDeaths)
Object of class SpatialPointsDataFrame
Coordinates:
               min      max
coords.x1 529160.3 529655.9
coords.x2 180857.9 181306.2
Is projected: TRUE 
proj4string :
[+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000
+y_0=-100000 +ellps=airy +units=m +no_defs]
Number of points: 250
Data attributes:
       Id        Count       
 Min.   :0   Min.   : 1.000  
 1st Qu.:0   1st Qu.: 1.000  
 Median :0   Median : 1.000  
 Mean   :0   Mean   : 1.956  
 3rd Qu.:0   3rd Qu.: 2.000  
 Max.   :0   Max.   :15.000  

Menampilkan Peta

Plot

data.shape <- readOGR(dsn, layer="Cholera_Deaths")
OGR data source with driver: ESRI Shapefile 
Source: "D:\SD\SnowGIS_SHP", layer: "Cholera_Deaths"
with 250 features
It has 2 fields
# menampilkan data dengan plot
plot(data.shape)

data.pump <- readOGR (dsn, layer = "Pumps")
OGR data source with driver: ESRI Shapefile 
Source: "D:\SD\SnowGIS_SHP", layer: "Pumps"
with 8 features
It has 1 fields
# menampilkan data dengan paket ggplot2
points(data.pump, col="red")

ggplot

# eksrak koordinat dengan fungsi coordinates
cholera.coords <- as.data.frame(coordinates(CholeraDeaths))
pumps <- readOGR(dsn, layer = "Pumps")
OGR data source with driver: ESRI Shapefile 
Source: "D:\SD\SnowGIS_SHP", layer: "Pumps"
with 8 features
It has 1 fields
pumps.coords <- as.data.frame(coordinates(pumps))
ggplot(cholera.coords) +
  geom_point(aes(x=coords.x1, y = coords.x2)) +
  geom_point(aes(x=coords.x1, y = coords.x2, col=I("red")),
               data = pumps.coords)

3b. Peta Choropleth

Choropleth maps are popular thematic maps used to represent statistical data through various shading patterns or symbols on predetermined geographic areas (i.e. countries). They are good at utilizing data to easily represent variability of the desired measurement, across a region.

Membaca SHP

Library yang digunakan untuk pembuatan peta choropleth ini adalah sf, tigris, ggplot2, dan dplyr. Untuk itu, install terlebih dahulu package tersebut, kemudian load untuk digunakan.

library(sf)
library(tigris)
library(ggplot2)
library(dplyr)

Untuk membuka file shp yang dibaca, maka menggunakan fungsi st_read dari package sf.

depok <- "D:\\SD\\idn_adm_bps_20200401_shp\\idn_admbnda_adm3_bps_20200401.shp"
datadepok <- st_read(depok)
Reading layer `idn_admbnda_adm3_bps_20200401' from data source `D:\SD\idn_adm_bps_20200401_shp\idn_admbnda_adm3_bps_20200401.shp' using driver `ESRI Shapefile'
Simple feature collection with 7069 features and 16 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: 95.01079 ymin: -11.00762 xmax: 141.0194 ymax: 6.07693
geographic CRS: WGS 84

Membaca database jumlah kepala keluarga per kecamatan di Depok

Data jumlah kepala keluarga per kecamatan di Kota Depok, didapatkan dari publikasi BPS Kota Depok Dalam Angka 2021. Data dibuat dalam format CSV, dengan key yang digunakan berasal dari kolom ADM3_PCODE pada data shp Kota Depok.

KKDepok <- read.csv("D:\\SD\\JKK_Depok.csv",
                  header=TRUE)

Merge Data

Untuk memunculkan peta maka dilakukan penggabungan antara data spasial yang ada dengan database csv yang sudah dibuat. Untuk melakukan merge data maka dilakukan menggunakan fungsi geo_join.

mergedDepok<- geo_join(spatial_data=datadepok, 
                       data_frame=KKDepok, 
                       by_sp="ADM3_PCODE", 
                       by_df="adm3_pcode",
                       how = "inner")

Menampilkan Plot Data

Untuk menampilkan plot data tersebut digunakan fungsi ggplot

mycol = c("#E9D7B8", "#E8C9B3", "#C59CA4", "#A48D9E", "#606D94")
pDepok <- ggplot() +  
          geom_sf(data=mergedDepok,aes(fill=jum_KK))+  
          scale_fill_gradientn(colours=mycol,name="Jumlah KK")+  
          labs(title = "Sebaran Kepala Keluarga di Kota Depok", subtitle ="Jumlah Kepala Keluarga per Kecamatan")
pDepok

Referensi

Anisa, R., Dito, G.A., dan Nurussadad, A.A. (February 20, 2021). P3a-Database Queries with R.Retrieved from https://newlms.ipb.ac.id/

Anisa, R., Dito, G.A., dan Nurussadad, A.A. (February 20, 2021). P3b. Combining Multiple Tables with SQL.Retrieved from https://newlms.ipb.ac.id/

Anisa, R., Dito, G.A., dan Nurussadad, A.A. (February 20, 2021). P3c. Working with Spatial Data.Retrieved from https://newlms.ipb.ac.id/

Badan Pusat Statistik Kota Depok (February, 2021). Kota Depok dalam Angka 2021: Depok Municipality in Figures 2021. Retrieved from https://depokkota.bps.go.id/publication

Nurussadad, A.A. (February 20, 2021). P3d-Peta Choropleth.Retrieved from https://newlms.ipb.ac.id/

Soleh, A.M. (2021). STA581 Sains Data: Data Gathering, Storage, and Retrieval (Data wrangling & Spatial Data).Retrieved from https://newlms.ipb.ac.id/

Nicole DeLorenzo, Amy Dugger. (Akses Februari 2021). Choloropeth Map. Retrieved from Choloropeth Map

Run Queries Safely. (Akses Februari 2021). Retrieved from https://db.rstudio.com/best-practices/run-queries-safely/

Using dplyr with databases. (Akses Februari 2021). Retrieved from https://db.rstudio.com/dplyr/