Dari bagian sebelumnya, mendapat ilham tentang model dan model building. Prinsip dasar dari membangun sebuah model melibat serangkaian proses tidak berurutan dan kontinuu terkait : * Eksplorasi — > Menemukan pattern * Pemilihan family model (berdasarkan kebutuhan dan kondisi riil data) * Model fitting * Repeat Satu hal yang perlu kita pahami adalah, carilah model paling optimal; yaitu model yang menghasilkan residual paling minimal. Membangun model hampir mirip dengan melukis. Kita harus tahu kapan untuk berhenti mencari kesempurnaan dari karya kita, dan berani menguji cobanya ke lapangan.
Untuk pembahasan ini, kita akan mulai dengan load seluruh data dan package yang kita butuhkan.
Jika kita ingat kembali pada dataset ‘diamonds’, ada satu fakta menarik di mana berlian berkualitas rendah (poor cuts, bad color, dan inferior clarity) memiliki harga lebih mahal daripada berlian berkualitas tinggi.
diamonds %>% ggplot(aes(cut, price)) +geom_boxplot()
diamonds %>% ggplot(aes(color,price)) + geom_boxplot()
diamonds %>% ggplot(aes(clarity, price)) + geom_boxplot()
Kenapa bisa seperti itu?
Jawabannya ada pada eksplorasi data carat vs price.
ggplot(diamonds, aes(carat, price)) + geom_hex(bins = 50)
# Jika bingung, silahkan lihat pada grafik garis berikut
ggplot(diamonds, aes(carat, price)) + geom_line()
Yup, grafik di atas menunjukkan hubungan linier positif antara carat dengan price diamond; dan hubungan itu sangat kuat. Kita mungkin bisa membuat hipotesis bahwa karat merupakan faktor siginigikan dalam penentuan harga diamond.
Namun untuk memperkuat analisa. Mari kita analisa bagaimana kondisi karat dalam berbagai kategori kualitas diamond
ggplot(diamonds, aes(cut, carat)) + geom_boxplot()
ggplot(diamonds, aes(clarity, carat)) + geom_boxplot()
ggplot(diamonds, aes(color, carat)) + geom_boxplot()
Pada boxplot ditunjukkan bahwa diamond dengan carat tinggi terdistribusi lebih banyak pada diamond dengan kualitas renda. Ini memperkuat hipotesis kita bahwa carat merupakan penentu utama dari harga diamond.
Setelah memiliki hipotesis secara visual, mari kita coba buktikan dugaan kita melalui modelling. Kita tidak bisa terlalu cepat mengambil kesimpulan carat sebagai satu-satunya variabel yang berpengaruh terhadap harga bukan?
Nah, sebelum lebih jauh, satu hal yg perlu kita pahami saat berhadapan dengan big data seperti diamonds, ada baiknya kita memperhatikan distribusi masing-masing data. (sebenarnya, lebih sempurna jika kita melakukan ini pada setiap proses analisa data)
Untuk melakukannya, kita bisa menggunakan fungsi summary().
summary(diamonds)
## carat cut color clarity depth
## Min. :0.2000 Fair : 1610 D: 6775 SI1 :13065 Min. :43.00
## 1st Qu.:0.4000 Good : 4906 E: 9797 VS2 :12258 1st Qu.:61.00
## Median :0.7000 Very Good:12082 F: 9542 SI2 : 9194 Median :61.80
## Mean :0.7979 Premium :13791 G:11292 VS1 : 8171 Mean :61.75
## 3rd Qu.:1.0400 Ideal :21551 H: 8304 VVS2 : 5066 3rd Qu.:62.50
## Max. :5.0100 I: 5422 VVS1 : 3655 Max. :79.00
## J: 2808 (Other): 2531
## table price x y
## Min. :43.00 Min. : 326 Min. : 0.000 Min. : 0.000
## 1st Qu.:56.00 1st Qu.: 950 1st Qu.: 4.710 1st Qu.: 4.720
## Median :57.00 Median : 2401 Median : 5.700 Median : 5.710
## Mean :57.46 Mean : 3933 Mean : 5.731 Mean : 5.735
## 3rd Qu.:59.00 3rd Qu.: 5324 3rd Qu.: 6.540 3rd Qu.: 6.540
## Max. :95.00 Max. :18823 Max. :10.740 Max. :58.900
##
## z
## Min. : 0.000
## 1st Qu.: 2.910
## Median : 3.530
## Mean : 3.539
## 3rd Qu.: 4.040
## Max. :31.800
##
Dari summary ini kita bisa mengetahu gambaran umum tentang sebaran data. Namun ada satu parameter yang kurang di sini yaitu modus (mode). Untuk itu, mari kita buat terlebih dahulu fungsi modus kita yang kita beri nama modes().
# mode fucntion
modes <- function(x){
ux <- unique(x)
tab <- tabulate(match(x,ux))
ux[tab == max(tab)]
}
Setelah itu, kita mulai lakukan analisa modus.
modes(diamonds$carat)
## [1] 0.3
modes(diamonds$depth)
## [1] 62
modes(diamonds$table)
## [1] 56
modes(diamonds$price)
## [1] 605
modes(diamonds$x)
## [1] 4.37
modes(diamonds$y)
## [1] 4.34
modes(diamonds$z)
## [1] 2.7
Di sini kita bisa mengetahui pattern terkuat berada dari variabel ‘carat’ terhadap ‘price’.
ggplot(diamonds,aes(carat, price)) +
geom_hex(bins = 50)
Jika kita ingin mengevaluasi dampak attribut diamond lain terhadap harga, kita bisa membangun model untuk memisahkan efek dari ‘carat’ Caranya : * Pertama, kita transformasikan carat dan price menjadi log.
diamonds2 <- diamonds %>%
mutate(lprice = log2(price), lcarat = log2(carat))
diamonds2
## # A tibble: 53,940 x 12
## carat cut color clarity depth table price x y z lprice lcarat
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43 8.35 -2.12
## 2 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31 8.35 -2.25
## 3 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31 8.35 -2.12
## 4 0.29 Premium I VS2 62.4 58 334 4.2 4.23 2.63 8.38 -1.79
## 5 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75 8.39 -1.69
## 6 0.24 Very G~ J VVS2 62.8 57 336 3.94 3.96 2.48 8.39 -2.06
## 7 0.24 Very G~ I VVS1 62.3 57 336 3.95 3.98 2.47 8.39 -2.06
## 8 0.26 Very G~ H SI1 61.9 55 337 4.07 4.11 2.53 8.40 -1.94
## 9 0.22 Fair E VS2 65.1 61 337 3.87 3.78 2.49 8.40 -2.18
## 10 0.23 Very G~ H VS1 59.4 61 338 4 4.05 2.39 8.40 -2.12
## # ... with 53,930 more rows
Apa gunanya transformasi log? Hal ini untuk mempermudah kita melihat hubungan antara carat dan price. Transformasi log akan membuat pattern linier dan memudahkan kita untuk bekerja.
ggplot(diamonds2, aes(lcarat, lprice)) + geom_hex(bins = 50)
Lihat? hasil transformasi log membuat hubungan linier kedua variabel di atas semakin jelas. Langkah selanjutnya dalam mengeluarkan pola linier dari data adalah dengan membuat hubungan carat vs price eksplisit melalui model fitting.
mod_diamonds <- lm(lprice~lcarat, data = diamonds2)
mod_diamonds
##
## Call:
## lm(formula = lprice ~ lcarat, data = diamonds2)
##
## Coefficients:
## (Intercept) lcarat
## 12.189 1.676
summary(mod_diamonds)
##
## Call:
## lm(formula = lprice ~ lcarat, data = diamonds2)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.17606 -0.24456 -0.00853 0.24002 1.93023
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 12.188841 0.001969 6190.9 <2e-16 ***
## lcarat 1.675817 0.001934 866.6 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.3789 on 53938 degrees of freedom
## Multiple R-squared: 0.933, Adjusted R-squared: 0.933
## F-statistic: 7.51e+05 on 1 and 53938 DF, p-value: < 2.2e-16
Langkah selanjutnya adalah dengan mencoba memvisualisasikan model dengan sedikit perubahan.
# Membuat objek baru untuk visualisasi model menggunakan data_grid()
grid <- diamonds2 %>%
data_grid(carat) %>%
mutate(lcarat= log2(carat)) %>%
add_predictions(mod_diamonds, "lprice") %>%
mutate(price = 2 ^ lprice)
# lihat hasilnya
grid
## # A tibble: 273 x 4
## carat lcarat lprice price
## <dbl> <dbl> <dbl> <dbl>
## 1 0.2 -2.32 8.30 315.
## 2 0.21 -2.25 8.42 341.
## 3 0.22 -2.18 8.53 369.
## 4 0.23 -2.12 8.64 398.
## 5 0.24 -2.06 8.74 427.
## 6 0.25 -2 8.84 457.
## 7 0.26 -1.94 8.93 488.
## 8 0.27 -1.89 9.02 520.
## 9 0.28 -1.84 9.11 553.
## 10 0.29 -1.79 9.20 587.
## # ... with 263 more rows
Sekarang, kita visualisasikan model di atas
ggplot(diamonds2, aes(carat, price)) +
geom_hex(bins = 50) +
geom_line(data = grid, color ="red", size = 1)
Perhatikan bahwa dalam model di atas, kita tidak lagi menggunakan prediksi linier pada variabel ‘price’ (karena setelah mendapat nilai prediksi lprice, kita mengubahnya lagi menjadi ‘price’)
Apakah transformasi ini berdampak ? Kita bisa cek pada residualnya.
# Cek residual
diamonds2 <- diamonds2 %>% add_residuals(mod_diamonds, "lresid")
diamonds2 <- diamonds2 %>% mutate(resid = 2^lresid)
diamonds2
## # A tibble: 53,940 x 14
## carat cut color clarity depth table price x y z lprice lcarat
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43 8.35 -2.12
## 2 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31 8.35 -2.25
## 3 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31 8.35 -2.12
## 4 0.29 Premium I VS2 62.4 58 334 4.2 4.23 2.63 8.38 -1.79
## 5 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75 8.39 -1.69
## 6 0.24 Very G~ J VVS2 62.8 57 336 3.94 3.96 2.48 8.39 -2.06
## 7 0.24 Very G~ I VVS1 62.3 57 336 3.95 3.98 2.47 8.39 -2.06
## 8 0.26 Very G~ H SI1 61.9 55 337 4.07 4.11 2.53 8.40 -1.94
## 9 0.22 Fair E VS2 65.1 61 337 3.87 3.78 2.49 8.40 -2.18
## 10 0.23 Very G~ H VS1 59.4 61 338 4 4.05 2.39 8.40 -2.12
## # ... with 53,930 more rows, and 2 more variables: lresid <dbl>, resid <dbl>
Untuk lebih mudah, kita lihat visualnya
ggplot(diamonds2, aes(lcarat, resid)) + geom_hex(bins = 50)
ggplot(diamonds2, aes(lcarat, lresid)) + geom_hex(bins = 50)
Kita bisa menggunakan ‘lresid’ pada attribute diamonds lain
ggplot(diamonds2, aes(cut, lresid)) + geom_boxplot()
Pada bagian ini, kita akan mempelajari tiga ide yang membantu untuk mengolah model big data. * Menggunakan banyak model sederhana untuk memahami dataset yang kompleks * Menggunakan list-columns untuk menyimpan struktur data abritrari dalam data frame. Sebagai contoh, list-column akan memungkinkan kita memiliki sebuah kolom yang memiliki model linier * Menggunakan package ‘broom’ untuk mengubah model menjadi data yang tidy. Ini adalah teknik yang sangat berguna untuk bekerja dengan banyak model.
Kita akan belajar bagaimana untuk : * Kenapa menaruh list dalam data frame bisa dianggap valid * 3 cara utama untuk membuat list-column * Cara mengembalikan list-column menjadi atomic vector * dan menata data menggunkan broom
Untuk mempelajari bagian ini, package awal yang dibutuhkan adalah
library(tidyverse)
library(modelr)
Sebagai awalan, kita akan mulai dengan menggunakan dataset bernama ‘gapminder’.
library(gapminder)
## Warning: package 'gapminder' was built under R version 4.1.2
gapminder
## # A tibble: 1,704 x 6
## country continent year lifeExp pop gdpPercap
## <fct> <fct> <int> <dbl> <int> <dbl>
## 1 Afghanistan Asia 1952 28.8 8425333 779.
## 2 Afghanistan Asia 1957 30.3 9240934 821.
## 3 Afghanistan Asia 1962 32.0 10267083 853.
## 4 Afghanistan Asia 1967 34.0 11537966 836.
## 5 Afghanistan Asia 1972 36.1 13079460 740.
## 6 Afghanistan Asia 1977 38.4 14880372 786.
## 7 Afghanistan Asia 1982 39.9 12881816 978.
## 8 Afghanistan Asia 1987 40.8 13867957 852.
## 9 Afghanistan Asia 1992 41.7 16317921 649.
## 10 Afghanistan Asia 1997 41.8 22227415 635.
## # ... with 1,694 more rows
Mari kita buat pertanyaan riset terlebih dahulu : * Bagaimana ekspektasi usia (lifeExp) berubah sepanjang waktu (year) untuk masing-masing negara(country)?
Seperti biasa, praktik termudah adalah dengan membuat plot untuk menjawab pertanyaan tersebut
gapminder %>%
ggplot(aes(year, lifeExp, group = country)) +
geom_line(alpha = 1/3)
Pada data di atas,overall, lifeExp mengalami kenaikan sepanjang waktu. Namun dapat kita lihat juga beberapa negara yang memiliki trend berbeda dari kebanyakan. Pertanyaan : Bagaimana cara agar kita bisa melihat pertumbuhan negara-negara seperti itu?
Jika kita hanya membahas satu negara, tentu penyusunannya lebih masuk akal.
nz <- filter(gapminder, country == "New Zealand")
nz %>% ggplot(aes(year, lifeExp)) +
geom_line() +
ggtitle("Full data = ")
nz_mod <- lm(lifeExp~year, data = nz)
nz %>% add_predictions(nz_mod) %>%
ggplot(aes(year, pred)) +
geom_line() +
ggtitle("Linier trend +")
nz %>%
add_residuals(nz_mod) %>%
ggplot(aes(year, resid)) +
geom_line() +
geom_hline(yintercept = 0, color = "white", size = 3) +
ggtitle("Remaining pattern")
Lalu, bagaimana cara kita menarik data negara-negara dengan trend berbeda secara keseluruhan? R memberikan tool berguna yang memungkinkan kita untuk menata data frame khusus di dalam data frame lain, dan itu menggunakan fungsi nest().
by_country <- gapminder %>% group_by(country, continent) %>%
nest()
by_country
## # A tibble: 142 x 3
## # Groups: country, continent [142]
## country continent data
## <fct> <fct> <list>
## 1 Afghanistan Asia <tibble [12 x 4]>
## 2 Albania Europe <tibble [12 x 4]>
## 3 Algeria Africa <tibble [12 x 4]>
## 4 Angola Africa <tibble [12 x 4]>
## 5 Argentina Americas <tibble [12 x 4]>
## 6 Australia Oceania <tibble [12 x 4]>
## 7 Austria Europe <tibble [12 x 4]>
## 8 Bahrain Asia <tibble [12 x 4]>
## 9 Bangladesh Asia <tibble [12 x 4]>
## 10 Belgium Europe <tibble [12 x 4]>
## # ... with 132 more rows
Dengan menggunakan nest(), akan muncul satu kolom baru bernama’data’ yang cukup unik karena berisikan list dari data-data frame lain.
Contoh, jika kita take out salah satu row, maka akan muncul dataframe berisi variabel lengkap untuk negara masing-masing.
by_country$data[1]
## [[1]]
## # A tibble: 12 x 4
## year lifeExp pop gdpPercap
## <int> <dbl> <int> <dbl>
## 1 1952 28.8 8425333 779.
## 2 1957 30.3 9240934 821.
## 3 1962 32.0 10267083 853.
## 4 1967 34.0 11537966 836.
## 5 1972 36.1 13079460 740.
## 6 1977 38.4 14880372 786.
## 7 1982 39.9 12881816 978.
## 8 1987 40.8 13867957 852.
## 9 1992 41.7 16317921 649.
## 10 1997 41.8 22227415 635.
## 11 2002 42.1 25268405 727.
## 12 2007 43.8 31889923 975.
Lihat?
Setiap elemen dalam kolom ‘data’, adalah dataframe lain yang berisikan seluruh data lengkap masing-masing negara. Apa dampaknya? Dengan dataframe masing-masing negara kini sudah tersusun dalam bentuk list di dalam variabel ‘data’, maka kita bisa menerapkan hal yang sama pada list pada umumnya.
Yep… fungsi map; fitur yang menerapkan satu fungsi pada seluruh elemen list secara simultan. Inilah yang disebut dengan ‘nested dataframe’.
Sekarang, saatnya kita melakukan fitting model. Buat sebuah fungsi yang berisikan model fitting yang kita inginkan.
country_model <- function(df){
lm(lifeExp~year, data = df)
}
Lalu, kita terapkan fungsi map. Kita bisa membuat objek baru untuk menyimpan hasil model, atau menjadikannya kolom baru dalam dataframe by_country.
by_country <- by_country %>%
mutate(model = map(data, country_model))
by_country
## # A tibble: 142 x 4
## # Groups: country, continent [142]
## country continent data model
## <fct> <fct> <list> <list>
## 1 Afghanistan Asia <tibble [12 x 4]> <lm>
## 2 Albania Europe <tibble [12 x 4]> <lm>
## 3 Algeria Africa <tibble [12 x 4]> <lm>
## 4 Angola Africa <tibble [12 x 4]> <lm>
## 5 Argentina Americas <tibble [12 x 4]> <lm>
## 6 Australia Oceania <tibble [12 x 4]> <lm>
## 7 Austria Europe <tibble [12 x 4]> <lm>
## 8 Bahrain Asia <tibble [12 x 4]> <lm>
## 9 Bangladesh Asia <tibble [12 x 4]> <lm>
## 10 Belgium Europe <tibble [12 x 4]> <lm>
## # ... with 132 more rows
Coba kita cek,
by_country$model[1]
## [[1]]
##
## Call:
## lm(formula = lifeExp ~ year, data = df)
##
## Coefficients:
## (Intercept) year
## -507.5343 0.2753
Seperti yang kita lihat, saat kita call salah satu elemen model, akan muncul hasil dari model fitting tersebut.
Menjadikan hasil estimasi model sebagai kolom dari dataframe by_country merupakan praktik yang dianjukan, karena untuk menjaga keakuratan data. Karena saat terpisah, dan kita melakukan manipulasi pada salah satu vector, hasil yang ada akan tertukar dan kita memperolah prediksi yang salah.
Sekarang, setelah selesai dengan model yg berisi model fitting masing-masing negara dalam kolom ‘data’, bagaimana kita menghitung residualnya.
Seperti yang kita tahu, ‘add_residuals(data, function)’ Nah dalam dataframe ini, kita akan menerapkan mapping menggunakan dua vector, yaitu ‘data’ yang berisi data frame masing-masing negara, dan ‘model’ yang menjadi vector fungsi.
by_country <- by_country %>%
mutate(resids = map2(data,model,add_residuals))
by_country
## # A tibble: 142 x 5
## # Groups: country, continent [142]
## country continent data model resids
## <fct> <fct> <list> <list> <list>
## 1 Afghanistan Asia <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 2 Albania Europe <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 3 Algeria Africa <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 4 Angola Africa <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 5 Argentina Americas <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 6 Australia Oceania <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 7 Austria Europe <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 8 Bahrain Asia <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 9 Bangladesh Asia <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 10 Belgium Europe <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## # ... with 132 more rows
# kita cek
by_country$resids[1]
## [[1]]
## # A tibble: 12 x 5
## year lifeExp pop gdpPercap resid
## <int> <dbl> <int> <dbl> <dbl>
## 1 1952 28.8 8425333 779. -1.11
## 2 1957 30.3 9240934 821. -0.952
## 3 1962 32.0 10267083 853. -0.664
## 4 1967 34.0 11537966 836. -0.0172
## 5 1972 36.1 13079460 740. 0.674
## 6 1977 38.4 14880372 786. 1.65
## 7 1982 39.9 12881816 978. 1.69
## 8 1987 40.8 13867957 852. 1.28
## 9 1992 41.7 16317921 649. 0.754
## 10 1997 41.8 22227415 635. -0.534
## 11 2002 42.1 25268405 727. -1.54
## 12 2007 43.8 31889923 975. -1.22
Oke… lalu sekarang bagaimana cara memvisualkan prediksi dari masing-masing negara tersebut? Akan sulit jika menggunakan ggplot pada dataframe by_country begitu saja yang terdiri dari data struktur list-coloumn.
Solusi paling efisien adalah dengan membuka nest data frame khusus data ‘resids’; caranya dengan menggunakan function unnest()
resids <- unnest(by_country,resids)
resids
## # A tibble: 1,704 x 9
## # Groups: country, continent [142]
## country continent data model year lifeExp pop gdpPercap resid
## <fct> <fct> <list> <list> <int> <dbl> <int> <dbl> <dbl>
## 1 Afghanistan Asia <tibble ~ <lm> 1952 28.8 8.43e6 779. -1.11
## 2 Afghanistan Asia <tibble ~ <lm> 1957 30.3 9.24e6 821. -0.952
## 3 Afghanistan Asia <tibble ~ <lm> 1962 32.0 1.03e7 853. -0.664
## 4 Afghanistan Asia <tibble ~ <lm> 1967 34.0 1.15e7 836. -0.0172
## 5 Afghanistan Asia <tibble ~ <lm> 1972 36.1 1.31e7 740. 0.674
## 6 Afghanistan Asia <tibble ~ <lm> 1977 38.4 1.49e7 786. 1.65
## 7 Afghanistan Asia <tibble ~ <lm> 1982 39.9 1.29e7 978. 1.69
## 8 Afghanistan Asia <tibble ~ <lm> 1987 40.8 1.39e7 852. 1.28
## 9 Afghanistan Asia <tibble ~ <lm> 1992 41.7 1.63e7 649. 0.754
## 10 Afghanistan Asia <tibble ~ <lm> 1997 41.8 2.22e7 635. -0.534
## # ... with 1,694 more rows
Sekarang, kita kembali memiliki dataframe yang benar… Kita bisa melakukan visual
resids %>%
ggplot(aes(year, resid)) +
geom_line(aes(group = country), alpha = 1/3) +
facet_wrap(~continent)
Pada plot residual per continent di atas, kita bisa melihat adanya yang tidak beres di Afrika. Untuk mengetahui yang mana yang salah, kita bisa menggunakan ukuran kualitas model (R square, adj.R Square, p.value, dll)
Untuk mencari ukuran kualitas model dengan memanfaatkan tool dari broom,kita bisa menggunakan broom::glance
broom::glance(nz_mod)
## # A tibble: 1 x 12
## r.squared adj.r.squared sigma statistic p.value df logLik AIC BIC
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0.954 0.949 0.804 205. 0.0000000541 1 -13.3 32.6 34.1
## # ... with 3 more variables: deviance <dbl>, df.residual <int>, nobs <int>
Nah, skg kita terapkan ‘glance’ pada dataframe by_country untuk mencari kualitas model per negara.
glance <- by_country %>%
mutate(glance = map(model,broom::glance)) %>%
unnest(glance, .drop = TRUE)
## Warning: The `.drop` argument of `unnest()` is deprecated as of tidyr 1.0.0.
## All list-columns are now preserved.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
glance
## # A tibble: 142 x 17
## # Groups: country, continent [142]
## country continent data model resids r.squared adj.r.squared sigma statistic
## <fct> <fct> <lis> <lis> <list> <dbl> <dbl> <dbl> <dbl>
## 1 Afghani~ Asia <tib~ <lm> <tibb~ 0.948 0.942 1.22 181.
## 2 Albania Europe <tib~ <lm> <tibb~ 0.911 0.902 1.98 102.
## 3 Algeria Africa <tib~ <lm> <tibb~ 0.985 0.984 1.32 662.
## 4 Angola Africa <tib~ <lm> <tibb~ 0.888 0.877 1.41 79.1
## 5 Argenti~ Americas <tib~ <lm> <tibb~ 0.996 0.995 0.292 2246.
## 6 Austral~ Oceania <tib~ <lm> <tibb~ 0.980 0.978 0.621 481.
## 7 Austria Europe <tib~ <lm> <tibb~ 0.992 0.991 0.407 1261.
## 8 Bahrain Asia <tib~ <lm> <tibb~ 0.967 0.963 1.64 291.
## 9 Banglad~ Asia <tib~ <lm> <tibb~ 0.989 0.988 0.977 930.
## 10 Belgium Europe <tib~ <lm> <tibb~ 0.995 0.994 0.293 1822.
## # ... with 132 more rows, and 8 more variables: p.value <dbl>, df <dbl>,
## # logLik <dbl>, AIC <dbl>, BIC <dbl>, deviance <dbl>, df.residual <int>,
## # nobs <int>
Dengan menggunakan broom::glance sekarang kita punya parameter kualitas model untuk masing-masing negara yang tersusun menjadi dataframe. Struktur ini memungkinkan kita untuk melihat dan memfilter mana negara yang tidak sesuai dengan model.
glance %>% arrange(r.squared)
## # A tibble: 142 x 17
## # Groups: country, continent [142]
## country continent data model resids r.squared adj.r.squared sigma statistic
## <fct> <fct> <lis> <lis> <list> <dbl> <dbl> <dbl> <dbl>
## 1 Rwanda Africa <tib~ <lm> <tibb~ 0.0172 -0.0811 6.56 0.175
## 2 Botswana Africa <tib~ <lm> <tibb~ 0.0340 -0.0626 6.11 0.352
## 3 Zimbabwe Africa <tib~ <lm> <tibb~ 0.0562 -0.0381 7.21 0.596
## 4 Zambia Africa <tib~ <lm> <tibb~ 0.0598 -0.0342 4.53 0.636
## 5 Swazila~ Africa <tib~ <lm> <tibb~ 0.0682 -0.0250 6.64 0.732
## 6 Lesotho Africa <tib~ <lm> <tibb~ 0.0849 -0.00666 5.93 0.927
## 7 Cote d'~ Africa <tib~ <lm> <tibb~ 0.283 0.212 3.93 3.95
## 8 South A~ Africa <tib~ <lm> <tibb~ 0.312 0.244 4.74 4.54
## 9 Uganda Africa <tib~ <lm> <tibb~ 0.342 0.276 3.19 5.20
## 10 Congo, ~ Africa <tib~ <lm> <tibb~ 0.348 0.283 2.43 5.34
## # ... with 132 more rows, and 8 more variables: p.value <dbl>, df <dbl>,
## # logLik <dbl>, AIC <dbl>, BIC <dbl>, deviance <dbl>, df.residual <int>,
## # nobs <int>
Terlihat pada dataframe di atas, menunjukkan bahwa seluruh negara di benua Africa tidak sesuai dengan model yang kita buat.