Pendahuluan

Rumah adalah salah satu bangunan yang memiliki lantai, dinding dan atap yang berfungsi sebagai tempat tinggal oleh individu, sekumpulan individu maupun keluarga sehingga mampu memberikan kenyamanan dan perlindungan bagi penghuninya dari berbagai ancaman sosial dan gangguan alam seperti penyakit dan bencana alam. Perumahan yang layak merupakan salah satu kebutuhan esensial bagi setiap orang yang pemenuhannya dijamin oleh UUD 1945 pasal 28 H ayat 1 bahwa setiap orang berhak hidup sejahtera lahir dan batin, bertempat tinggal, dan mendapatkan lingkungan hidup yang baik dan sehat serta berhak memperoleh pelayanan kesehatan. Menurut Badan Pusat Statistik, sejak tahun 2019 rumah tangga diklasifikasikan memiliki akses terhadap hunian/rumah layak huni apabila memenuhi 4 (empat) kriteria, yaitu:

  1. kecukupan luas tempat tinggal minimal 7,2 m2 per kapita (sufficient living space)

  2. memiliki akses terhadap air minum layak

  3. memiliki akses terhadap sanitasi layak

  4. ketahanan bangunan (durable housing), yaitu atap terluas berupa beton/ genteng/ seng/ kayu/ sirap; dinding terluas berupa tembok/ plesteran anyaman bambu/kawat, kayu/papan dan batang kayu; dan lantai terluas berupa marmer/ granit/ keramik/ parket/vinil/karpet/ ubin/tegel/teraso/ kayu/papan/ semen/bata merah.

Data Wrangling dan Eksplorasi Data

1. Import Library

Untuk melakukan analisis, beberapa packages yang digunakan adalah sebagai berikut:

# Import library untuk data wrangling
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.2     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.2     ✔ tibble    3.2.1
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.0
## ✔ purrr     1.0.1     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(dplyr)

# Import library untuk visualisasi
library(factoextra) # Visualisasi hasil clustering
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(gridExtra) # Visualisasi karakteristik cluster
## 
## Attaching package: 'gridExtra'
## 
## The following object is masked from 'package:dplyr':
## 
##     combine
library(GGally) # Correlation matrix
## Registered S3 method overwritten by 'GGally':
##   method from   
##   +.gg   ggplot2
library(ggiraphExtra)
library(sf) # Read data map
## Linking to GEOS 3.11.2, GDAL 3.6.2, PROJ 9.2.0; sf_use_s2() is TRUE
library(plotly) # Interactive Plotting
## 
## Attaching package: 'plotly'
## 
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## 
## The following object is masked from 'package:stats':
## 
##     filter
## 
## The following object is masked from 'package:graphics':
## 
##     layout
library(Rtsne)


# Machine Learning - Clustering 
library(cluster)
library(factoextra)
library(mvnTest)
## Loading required package: mvtnorm

2. Read Data

Data pada penelitian ini merupakan data Sekunder, yang berisikan informasi mengenai indikator rumah layak huni. Data yang digunakan diperoleh dari situs Badan Pusat Statistik (https://www.bps.go.id/) tahun 2022.

#Input data
data = rio::import("https://raw.githubusercontent.com/yoginurhamid/TPG/main/Data/Data%20TPG%20Rumah%20tidak%20layak%20huni.csv")

#Cek struktur data
glimpse(data) 
## Rows: 35
## Columns: 5
## $ Provinsi                                                                                                                                                   <chr> …
## $ `Persentase Rumah Tangga menurut Provinsi, Tipe Daerah dan Luas Hunian per kapita <= 7,2 m2 (Persen)`                                                      <dbl> …
## $ `Persentase Rumah Tangga menurut Provinsi dan Sumber Air Minum Layak (Persen)`                                                                             <dbl> …
## $ `Proporsi Rumah Tangga Yang Memiliki Akses Terhadap Layanan Sanitasi Layak (Persen)`                                                                       <dbl> …
## $ `Persentase Rumah Tangga yang Menempati Rumah dengan Ketahanan Bangunan (Atap, Lantai, Dinding) Memenuhi Syarat menurut Provinsi dan Tipe Daerah (Persen)` <dbl> …

3. Data Cleaning

Dibagian ini variabel data akan disesuaikan tipe datanya, kemudian agar memudahkan dalam kodingan tiap variabel akan diganti menjadi X1, X2, dst, dan untuk variabel provinsi akan dijadikan sebagai rowname atau nama dari tiap barisnya.

#Meng-assign nilai dari kolom Provinsi menjadi rownames
#rownames(data) = data$Provinsi

#Membuang peubah provinsi dan amatan Indonesia
indikator = data[-35,-1]

#Mengubah nama kolom
colnames(indikator)
## [1] "Persentase Rumah Tangga menurut Provinsi, Tipe Daerah dan Luas Hunian per kapita <= 7,2 m2 (Persen)"                                                     
## [2] "Persentase Rumah Tangga menurut Provinsi dan Sumber Air Minum Layak (Persen)"                                                                            
## [3] "Proporsi Rumah Tangga Yang Memiliki Akses Terhadap Layanan Sanitasi Layak (Persen)"                                                                      
## [4] "Persentase Rumah Tangga yang Menempati Rumah dengan Ketahanan Bangunan (Atap, Lantai, Dinding) Memenuhi Syarat menurut Provinsi dan Tipe Daerah (Persen)"
names(indikator)[names(indikator)==c("Persentase Rumah Tangga menurut Provinsi, Tipe Daerah dan Luas Hunian per kapita <= 7,2 m2 (Persen)","Persentase Rumah Tangga menurut Provinsi dan Sumber Air Minum Layak (Persen)","Proporsi Rumah Tangga Yang Memiliki Akses Terhadap Layanan Sanitasi Layak (Persen)","Persentase Rumah Tangga yang Menempati Rumah dengan Ketahanan Bangunan (Atap, Lantai, Dinding) Memenuhi Syarat menurut Provinsi dan Tipe Daerah (Persen)")] = c("x1","x2","x3","x4")

#cek data
str(indikator)
## 'data.frame':    34 obs. of  4 variables:
##  $ x1: num  7.47 8.79 6.39 7.56 3.9 ...
##  $ x2: num  89.7 92.1 85.2 90.1 79.2 ...
##  $ x3: num  77.5 82.3 69.3 84.1 79.5 ...
##  $ x4: num  93.3 89.3 97.4 94.2 95.2 ...

Keterangan:

  • x1 = Persentase rumah tangga menurut provinsi, tipe daerah dan luas hunian per kapita <= 7,2 m2 (persen)

  • x2 = Persentase Rumah Tangga menurut Provinsi dan Sumber Air Minum Layak (Persen)

  • x3 = Proporsi Rumah Tangga Yang Memiliki Akses Terhadap Layanan Sanitasi Layak (Persen)

  • x4 = Persentase Rumah Tangga yang Menempati Rumah dengan Ketahanan Bangunan (Atap, Lantai, Dinding) Memenuhi Syarat menurut Provinsi dan Tipe Daerah (Persen)

4. Data Exploration

Periksa Missing Value

indikator %>% 
  is.na() %>% 
  colSums()
## x1 x2 x3 x4 
##  0  0  0  0

Tidak terdapat missng value atau dapat dikatakan bahwa data sudah lengkap dan dapat dilanjutkan ke proses analisis.

Pengecekan Summary Data

summary(indikator)
##        x1               x2              x3              x4       
##  Min.   : 2.030   Min.   :65.39   Min.   :40.34   Min.   :42.02  
##  1st Qu.: 6.300   1st Qu.:81.58   1st Qu.:77.43   1st Qu.:84.26  
##  Median : 7.515   Median :89.83   Median :81.67   Median :90.98  
##  Mean   : 8.745   Mean   :87.64   Mean   :81.00   Mean   :85.44  
##  3rd Qu.:10.332   3rd Qu.:93.25   3rd Qu.:84.93   3rd Qu.:94.03  
##  Max.   :29.740   Max.   :98.42   Max.   :96.21   Max.   :97.91

Dari informasi diatas dapat diketahui bahwa tiap provinsi memiliki karakteristik tersendiri, maka dari itu provinsi-provinsi akan diklasterkan berdasarkan kemiripan dari karakteristiknya.

Periksa Korelasi Antar Peubah

#cek korelasi
ggcorr(indikator, label=TRUE)

  • Tidak terdapat korelasi yang tinggi antar peubah.

  • Terdapat beberapa peubah yang memiliki korelasi yang sedang yaitu 0.6 dan -0.6 sedangkan sisanya berkorelasi rendah.

  • Terdapat beberapa peubah yang tidak memiliki korelasi (nilai korelasi = 0), yaitu peubah x2 dan x3 dengan x4.

  • Peubah-peubah yang memiliki hubungan perlu diteliti terkait permasalahan multikolinearitas.

Pemeriksaan Masalah Data

1. Pemeriksaan Multikolinearitas

Pengujian multikolinearitas ini untuk melihat apakah ada variabel yang memberikan informasi yang sama dengan variabel lain atau biasa disebut redundan. Untuk menguji multikolinearitas akan dilihat dari nilai Variance Inflation Factor (VIF). Model dikatakan memiliki multikolinearitas jika nilai VIF > 10 yang mengindikasikan bahwa hasil estimasi yang kurang baik.

CekVIF <- function(data) {
  corr = as.matrix(cor(data))
  VIF = diag(solve(corr))
  
  return(VIF)
}

CekVIF(indikator)
##       x1       x2       x3       x4 
## 2.006802 1.819638 2.837839 1.253604

Tidak terdapat multikolinearitas pada data yang digunakan sehingga dapat dilakukan analisis selanjutnya.

2. Pendeteksian Outlier

Outlier adalah pengamatan yang sangat menyimpang dari pengamatan lain sehingga, menimbulkan kecurigaan yang dihasilkan oleh mekanisme yang berbeda. Pengecekan outlier akan dilihat melalui visualisasi data dengan Boxplot.

# membagi jendela grafik menajdi 1 baris dan 4 kolom
par(mfrow=c(1,4))

# Looping Box-Plot
type <- c("x1", "x2", "x3", "x4")
for (i in type){
  boxplot(indikator[,i],
       main = paste("Peubah", i))
}

  • Pada peubah x1, x3, dan x4 terdapat outlier. Sedangkan peubah x2 tidak memuat outlier.

  • Dalam beberapa penelitian outlier diperlakukan dengan cara dibuang. Tapi memperlakukan outlier sebagai noise dapat mengakibatkan hilangnya informasi penting yang tersembunyi. Di banyak bidang, outlier lebih penting daripada data normal, karena dapat menunjukkan perilaku menyimpang atau awal dari pola baru.

Metode K-Means untuk Clustering

Metode K-Means digunakan sebagai alternatif metode klaster untuk data dengan ukuran yang lebih besar. Hal ini dikarenakan metode ini memiliki kecepatan yang lebih tinggi jika dibandingkan dengan metode hirarki. Metode K-Means dapat digunakan untuk menjelaskan algoritma dalam penentuan suatu objek kedalam klaster tertentu berdasarkan rataan terdekat[4]. Dalam prosedur pembentukan K-Means Cluster terdapat langkah-langkah yang dapat dilakukan, antara lain:

  1. Tentukan banyaknya klaster (k) yang akan dibentuk.

  2. Random initialization: meletakkan k centroid secara random.

  3. Cluster assignment: assign masing-masing observasi ke cluster terdekat berdasarkan perhitungan jarak.

  4. Centroid update: menggeser centroid ke rata-rata (means) dari cluster yang terbentuk.

  5. Ulangi langkah 3 dan 4 sampai tidak ada observasi yang clusternya berubah lagi.

1. Standardisasi Data

Bertujuan untuk menyamakan skala data atau menghilangkan kontras antar variabel yang memiliki satuan berbeda.

indikator_scale = scale(indikator)
indikator_scale
##              x1          x2          x3          x4
## 1  -0.237002449  0.26225821 -0.35943694  0.55516820
## 2   0.008308204  0.57162105  0.13315819  0.27183556
## 3  -0.437711165 -0.30681665 -1.19848385  0.83779778
## 4  -0.220276723  0.30936284  0.31302696  0.61774042
## 5  -0.900456260 -1.07576791 -0.14890873  0.68664017
## 6   0.331672246 -0.16422966 -0.24293104  0.32315884
## 7  -0.460012133 -1.85490396 -0.14482081  0.62477101
## 8  -1.160634225 -0.76895126  0.27112571  0.01803139
## 9  -0.917181987 -0.85042954  1.08666704 -3.05292882
## 10 -0.329923151  0.53215501  0.68911619 -1.73680302
## 11  2.349909891  1.31001796  1.20521690 -2.78295430
## 12 -0.170099544  0.68747298 -0.71304258 -0.57183483
## 13 -1.247979685  0.72311973  0.34470839 -0.10148858
## 14 -0.889305776  1.12796493  1.55473461  0.54110703
## 15 -0.900456260  0.94336571  0.01358634 -0.02907354
## 16 -0.774084106  0.64546075  0.42135701 -0.76869125
## 17  0.058485383  1.37239977  1.52714111  0.56149573
## 18  0.372557355  0.98792414  0.21696068 -0.25124008
## 19  1.101055658 -0.11203263 -0.74574599 -1.59548823
## 20 -0.539923937 -0.91790374 -0.36659082  0.82514272
## 21 -0.424702267 -1.35330330 -0.68136115  0.37659130
## 22 -0.398684470 -1.45897044  0.15870773  0.18887464
## 23 -0.372666674 -0.06365491  0.95380943  0.74780627
## 24 -0.049302631  0.29535876  0.12498234  0.87646601
## 25 -0.058594701  0.82878687  0.31200497  0.44830328
## 26  0.816718310 -0.11457883 -0.61186640  0.52142138
## 27 -0.400542884  0.54997839  1.14900791  0.03701397
## 28 -0.084612498  0.89116868  0.62064342  0.44970940
## 29  0.623443250  1.08467960 -0.12029325  0.79983261
## 30  0.184857537 -1.10250297 -0.21635952  0.29433344
## 31  0.840877693  0.56780176 -0.46265709  0.40260447
## 32 -0.342932049  0.05856251 -0.16423846  0.52001527
## 33  0.727514436 -0.77277056 -0.76414166  0.71124722
## 34  3.901685612 -2.83264331 -4.15507665 -1.34660547
## attr(,"scaled:center")
##        x1        x2        x3        x4 
##  8.745294 87.640000 80.997059 85.443529 
## attr(,"scaled:scale")
##        x1        x2        x3        x4 
##  5.380932  7.854854  9.784912 14.223564
jarak <- get_dist(indikator)
fviz_dist(jarak, gradient = list(low="green", mid="white", high="purple"))

2. Penentuan Jumlah Cluster (k optimum)

Menentukan jumlah klaster paling optimum untuk membagi 33 provinsi yang ada di Indonesia. Pada dasarnya nilai k optimum dapat ditentukan sendiri oleh peneliti, selain itu nilai k dapat ditentukan juga menggunakan bantuan grafik silhouette dan Elbow berikut.

###Silhouette

fviz_nbclust(x = indikator, 
             FUNcluster = kmeans,
             method = 'silhouette',
             k.max = 10)

# Menentukan jumlah klaster menggunakan metode silhouette
nbclust_result_silwidth <- fviz_nbclust(
  x = indikator,
  FUNcluster = kmeans,
  method = 'silhouette',
  k.max = 10,
  verbose = FALSE  # Matikan tampilan pesan tambahan
)

# Menampilkan nilai rata-rata silhouette pada grafik
sil_values_kmeans <- nbclust_result_silwidth$data

colnames(sil_values_kmeans) <- c("banyak_cluster","average_silwidth")

# Menampilkan grafikA
print(sil_values_kmeans)
##    banyak_cluster average_silwidth
## 1               1        0.0000000
## 2               2        0.5795104
## 3               3        0.2686982
## 4               4        0.2103885
## 5               5        0.2902851
## 6               6        0.2829189
## 7               7        0.2802994
## 8               8        0.2148841
## 9               9        0.2397716
## 10             10        0.2324013

###Elbow

fviz_nbclust(x = indikator, 
             FUNcluster = kmeans,
             method = 'wss',
             k.max = 10)

# Menentukan jumlah klaster menggunakan metode elbow
nbclust_result_wss <- fviz_nbclust(
  x = indikator,
  FUNcluster = kmeans,
  method = 'wss',
  k.max = 10,
  verbose = FALSE  # Matikan tampilan pesan tambahan
)

# Menampilkan nilai wss pada grafik
wss_values_kmeans <- nbclust_result_wss$data

colnames(wss_values_kmeans) <- c("banyak_cluster","wss")

# Menampilkan grafikA
print(wss_values_kmeans)
##    banyak_cluster       wss
## 1               1 12827.346
## 2               2  7191.542
## 3               3  5756.010
## 4               4  3218.716
## 5               5  2578.630
## 6               6  2099.488
## 7               7  1651.640
## 8               8  1426.498
## 9               9  1715.396
## 10             10  1212.834

###Hiearchical Clustering

hc <- hclust(dist(indikator), method = "ward.D2")

# Contoh 2
#define linkage methods
m <- c( "average", "single", "complete", "ward")
names(m) <- c( "average", "single", "complete", "ward")

#function to compute agglomerative coefficient
ac <- function(x) {
  agnes(indikator, method = x)$ac
}

#calculate agglomerative coefficient for each clustering linkage method
sapply(m, ac)
##   average    single  complete      ward 
## 0.8348189 0.8046854 0.8613107 0.9031934
clust <- agnes(indikator, method = "ward")
clust
## Call:     agnes(x = indikator, method = "ward") 
## Agglomerative coefficient:  0.9031934 
## Order of objects:
##  [1] 1  32 4  24 2  25 28 29 3  33 6  26 31 5  20 7  21 22 30 8  12 13 15 18 16
## [26] 14 17 23 27 9  11 10 19 34
## Height (summary):
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   2.604   5.781  11.323  18.009  16.913 106.168 
## 
## Available components:
## [1] "order"     "height"    "ac"        "merge"     "diss"      "call"     
## [7] "method"    "order.lab" "data"
#produce dendrogram
pltree(clust, cex = 0.6, hang = -1, main = "Dendrogram") 

#compute distance matrix
d <- dist(indikator, method = "euclidean")

#perform hierarchical clustering using Ward's method
final_clust <- hclust(d, method = "ward.D2" )

#cut the dendrogram into 2 clusters
groups <- cutree(final_clust, k=2)

#find number of observations in each cluster
table(groups)
## groups
##  1  2 
## 29  5
#append cluster labels to original data
final_data <- cbind(data[-35,1], cluster = groups)
final_data
##                           cluster
## 1  "ACEH"                 "1"    
## 2  "SUMATERA UTARA"       "1"    
## 3  "SUMATERA BARAT"       "1"    
## 4  "RIAU"                 "1"    
## 5  "JAMBI"                "1"    
## 6  "SUMATERA SELATAN"     "1"    
## 7  "BENGKULU"             "1"    
## 8  "LAMPUNG"              "1"    
## 9  "KEP. BANGKA BELITUNG" "2"    
## 10 "KEP. RIAU"            "2"    
## 11 "DKI JAKARTA"          "2"    
## 12 "JAWA BARAT"           "1"    
## 13 "JAWA TENGAH"          "1"    
## 14 "DI YOGYAKARTA"        "1"    
## 15 "JAWA TIMUR"           "1"    
## 16 "BANTEN"               "1"    
## 17 "BALI"                 "1"    
## 18 "NUSA TENGGARA BARAT"  "1"    
## 19 "NUSA TENGGARA TIMUR"  "2"    
## 20 "KALIMANTAN BARAT"     "1"    
## 21 "KALIMANTAN TENGAH"    "1"    
## 22 "KALIMANTAN SELATAN"   "1"    
## 23 "KALIMANTAN TIMUR"     "1"    
## 24 "KALIMANTAN UTARA"     "1"    
## 25 "SULAWESI UTARA"       "1"    
## 26 "SULAWESI TENGAH"      "1"    
## 27 "SULAWESI SELATAN"     "1"    
## 28 "SULAWESI TENGGARA"    "1"    
## 29 "GORONTALO"            "1"    
## 30 "SULAWESI BARAT"       "1"    
## 31 "MALUKU"               "1"    
## 32 "MALUKU UTARA"         "1"    
## 33 "PAPUA BARAT"          "1"    
## 34 "PAPUA"                "2"
knitr::kable(
  cbind(c("1","2","3","4","5","6","7","8","9","10"),
        sil_values_kmeans$average_silwidth,wss_values_kmeans$wss),
  col.names=c("banyak_cluster","average_silwidth","elbow")
)
banyak_cluster average_silwidth elbow
1 0 12827.3457294118
2 0.57951036798724 7191.54159034483
3 0.268698157006044 5756.010475
4 0.210388486120705 3218.71626442308
5 0.29028508353269 2578.62985714286
6 0.282918933365156 2099.48768303419
7 0.280299406942361 1651.63978111111
8 0.214884063825177 1426.49840730159
9 0.23977161571419 1715.39552642857
10 0.232401255565058 1212.83400976191

Berdasarkan grafik dapat diperoleh nilai k optimum adalah 2.

3. Hasil Pembagian Cluster

clus<-kmeans(indikator,2)
clus
## K-means clustering with 2 clusters of sizes 29, 5
## 
## Cluster means:
##          x1       x2       x3       x4
## 1  7.612414 88.16897 81.64483 90.60069
## 2 15.316000 84.57200 77.24000 55.53200
## 
## Clustering vector:
##  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 
##  1  1  1  1  1  1  1  1  2  2  2  1  1  1  1  1  1  1  2  1  1  1  1  1  1  1 
## 27 28 29 30 31 32 33 34 
##  1  1  1  1  1  1  1  2 
## 
## Within cluster sum of squares by cluster:
## [1] 3723.037 3468.504
##  (between_SS / total_SS =  43.9 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"

4. Visualisasi

fviz_cluster(clus,indikator) + theme_classic()

fviz_cluster(object = clus, data = indikator, palette = "jco", ggtheme = theme_minimal())

clusplot(indikator,clus$cluster,color=T,shade=T)

tabel.clus<-data.frame(data[-35,1],clus$cluster)
tabel.clus
##            data..35..1. clus.cluster
## 1                  ACEH            1
## 2        SUMATERA UTARA            1
## 3        SUMATERA BARAT            1
## 4                  RIAU            1
## 5                 JAMBI            1
## 6      SUMATERA SELATAN            1
## 7              BENGKULU            1
## 8               LAMPUNG            1
## 9  KEP. BANGKA BELITUNG            2
## 10            KEP. RIAU            2
## 11          DKI JAKARTA            2
## 12           JAWA BARAT            1
## 13          JAWA TENGAH            1
## 14        DI YOGYAKARTA            1
## 15           JAWA TIMUR            1
## 16               BANTEN            1
## 17                 BALI            1
## 18  NUSA TENGGARA BARAT            1
## 19  NUSA TENGGARA TIMUR            2
## 20     KALIMANTAN BARAT            1
## 21    KALIMANTAN TENGAH            1
## 22   KALIMANTAN SELATAN            1
## 23     KALIMANTAN TIMUR            1
## 24     KALIMANTAN UTARA            1
## 25       SULAWESI UTARA            1
## 26      SULAWESI TENGAH            1
## 27     SULAWESI SELATAN            1
## 28    SULAWESI TENGGARA            1
## 29            GORONTALO            1
## 30       SULAWESI BARAT            1
## 31               MALUKU            1
## 32         MALUKU UTARA            1
## 33          PAPUA BARAT            1
## 34                PAPUA            2
indikator%>%
  mutate(cluster=clus$cluster)%>%
  group_by(cluster)%>%
  summarise_all("mean")
## # A tibble: 2 × 5
##   cluster    x1    x2    x3    x4
##     <int> <dbl> <dbl> <dbl> <dbl>
## 1       1  7.61  88.2  81.6  90.6
## 2       2 15.3   84.6  77.2  55.5