1 Pengantar

Ide dasar dari Multi-stage Maximization of Likelihood (MM) adalah Membagi proses maksimisasi menjadi 2 atau lebih proses dengan dimensi yang lebih kecil.

MM Memiliki berbagai sebutan, diantaranya:

  1. Inference Function for Margins (IFM) (Joe, 1996)

  2. Maximization by Parts (Song, 2005)

  3. Two Stages ML (Shih, 1995)

Penduga bersifat aproksimasi dan konsisten

2 MM pada Sebaran Normal

2.1 Sebaran Normal

Fungsi kepadatan peluang (Probability Density Function, PDF) dari distribusi normal diberikan oleh:

\[ f(x; \mu, \sigma) = \frac{1}{\sigma \sqrt{2\pi}} \exp\left(-\frac{(x - \mu)^2}{2\sigma^2}\right), \quad x \in \mathbb{R} \]

dengan: - \(f(x; \mu, \sigma)\) adalah fungsi kepadatan peluang untuk variabel acak \(x\), - \(\mu\) adalah rata-rata (mean), - \(\sigma\) adalah simpangan baku (standard deviation)

Secara analitik, kita dapat menghitung penduga dari sebaran normal pada laman berikut: MLE sebaran normal. Selanjutnya, kita akan belajar untuk menghitung penduga sebaran normal secara simultan maupun secara multi-stage likelihood (likelihood bertahap) menggunakan profiled likelihood.

2.2 Pendugaan Parameter Sebaran Normal [Analitik]

Misal dipunyai data dengan sebaran normal berukuran 200 dengan rerata (\(\mu\)) = 12 dan ragam 1 (\(\sigma^2 = 1\)).

rm(list=ls())   # Menghapus semua dataset dan variabel
graphics.off()  # Menutup semua gambar

library(purrr)
# Simulasi data normal dengan mean 12 dan ragam 1
set.seed(12345)
# Generate data dari distribusi normal
data <- rnorm(n = 200, mean = 12, sd = 1)
n <- length(data)
s <- sqrt(mean((data - mean(data))^2)) 
x.bar <- mean(data) 

hist(data, breaks = 10, probability = TRUE, col = "lightblue", border = "black",
     main = "Histogram Data Sebaran Normal (simulasi)", xlab = "Nilai", ylab = "Density")
abline(v = x.bar, col = "red", lwd = 2, lty = 2)
legend("topright", legend = paste("Mean:", round(x.bar, 2)), col = "red", lwd = 2, lty = 2)

Secara analitik, penduga parameter dari \(\mu\) dan \(\sigma^2\) diperoleh dengan menggunakan \(\bar{x}\) dan \(s\)

# MLE
MLE <- c(x.bar,s)
MLE
## [1] 12.14522  1.06362

2.3 Penduga Parameter Sebaran Normal Secara Simultan

Selanjutnya, kita akan menduga paremeter secara simultan.

#Pendugaan Simultan
data <- rnorm(n = 200, mean = 12, sd = 1)
means <- seq(10,30,by=0.01)
sds <- seq(0.1, 3, by=0.01)
l.simultan <- function(){
  llh_norm <- function(means, sds, y){
    llh <- sum(dnorm(y, means, sds, log=TRUE))
    return(llh)
  }
  ll <- sapply(means,function(i) sapply(sds, function(j) llh_norm(i,j,data))) 
  df <- data.frame(ll=ll)
  row.names(df) <- sds
  colnames(df) <- means
  max = which(df == max(df), arr.ind=TRUE)   
  #rownames(df[max[1],])
  df.colnames = colnames(df)
  #df.colnames[max[2]]
  tibble::tibble(rownames(df[max[1],]), df.colnames[max[2]])
}
l.simultan()

Visualisasi dari penduga simultan dapat menggunakan sintaks berikut.

# Visualisasi 3 Dimensi
library(plotly)
llh_norm <- function(means, sds, y) {
  sum(dnorm(y, means, sds, log=TRUE))
}

ll_matrix <- outer(means, sds, Vectorize(function(m, s) llh_norm(m, s, data)))  # Matriks log-likelihood
fig <- plot_ly(x = ~means, y = ~sds, z = ~ll_matrix, type = "surface") %>%
  layout(
    title = "Log-Likelihood 3D Surface",
    scene = list(
      xaxis = list(title = "mu"),
      yaxis = list(title = "Standar deviasi"),
      zaxis = list(title = "Log-Likelihood")
    )
  )

fig  # Tampilkan plot 3D

Ide dari sintaks diatas adalah sebagai berikut.

  1. Simulasi data acak dari distribusi normal.

  2. Menentukan rentang kandidat untuk \(\mu\) dan \(\sigma\).

  3. Menghitung log-likelihood untuk setiap pasangan (\(\mu, \sigma\)).

  4. Menyimpan hasil dalam dataframe.

  5. Mencari parameter terbaik yang memaksimumkan log-likelihood.

  6. Menghasilkan nilai MLE untuk \(\mu\) dan \(\sigma\).

2.4 Penduga Parameter Sebaran Normal (Profile Likelihood)

Kali ini, kita akan mencoba menduga parameter secara Multi-level (profile likelihood)

# Optimasi Profile likelihood 
l.profile <- function(){
  fprofile.mean = function(means) return(  ( sum((data-x.bar)^2)/sum((data-means)^2) )^(0.5*n)  )
  profile.mean= sapply(means,fprofile.mean)
  data.1 = data.frame(means,profile.mean)
  means2 <- data.1[which.max(data.1$profile.mean),1]
  llh_norm2 <- function(sds, y){
    llh <- sum(dnorm(y, means2, sds, log=TRUE))
    return(llh)
  }
  
  ll <- sapply(sds,function(i) llh_norm2(i,data)) 
  df <- data.frame(ll=ll, sds=sds)
  #df[which.max(df$ll),2]
  tibble::tibble(df[which.max(df$ll),2], means2)
  }
l.profile()
  1. Ide nya adalah Menentukan \(\mu\) terbaik terlebih dahulu menggunakan Profile Likelihood.
  • Fungsi fprofile.mean() menghitung profile likelihood untuk setiap kandidat \(\mu\).

-Ditetapkan \(\mu\) terbaik sebagai means2 dengan likelihood maksimum.

  1. Setelah \(\mu\) terbaik ditemukan, \(\sigma\) dihitung menggunakan Log-Likelihood.
  • Fungsi llh_norm2() menghitung log-likelihood untuk setiap kandidat \(\sigma\)

  • Ditetapkan \(\sigma\) terbaik sebagai nilai dengan log-likelihood maksimum.

Kedua pendekatan (Simultan maupun Parsial/Profile Likelihood) memberikan nilai penduga yang sama, hanya saja waktu yang dibutuhkan lebih cepat apabila menggunakan profiled likelihood. Berikut perbandingannya

library(microbenchmark)
microbenchmark(l.simultan(),l.profile(),times = 2)
# 1 detik : 1000 milidetik

3 MM Data VBGM

Misalkan dipunyai data berkaitan dengan bagaimana ikan tersebut bertumbuh seiring waktu.

Data dapat diakses pada link berikut: Data Ikan

Dari data tersebut kita punya data usia ikan (age) dan panjang ikan (length) dan jenis kelamin ikan (sex), dan pertumbuhan ikan mengikuti pertumbuhan Von Bertalanffy Growth Mmodel (VBGM) seperti Persamaan berikut.

\[\begin{equation} Y_i = \beta_1 - \beta_2 \exp^{-\beta_3 a_i} \end{equation}\]

\(\beta_1\) : panjang maksimum ikan (asimtotik), \(\beta_2\) : skala petumbuhan awal, \(\beta_3\) : laju pertumbuhan, dan \(a_i\): usia ikan.

Kita akan menghitung nilai \(\beta_1, \beta_2, \beta_3\) berdasarkan data yang dipunyai.

# Load library yang diperlukan
library(readxl)   # Untuk membaca file Excel
library(dplyr)    # Untuk manipulasi data

data_vonB <- read_excel("data vonB.xlsx")
str(data_vonB)
## tibble [28 × 3] (S3: tbl_df/tbl/data.frame)
##  $ age   : num [1:28] 0 0 1 1 2 2 3 3 4 4 ...
##  $ length: num [1:28] 9.4 9.4 12.6 12.6 15.7 15.7 17.5 17.5 19.9 20.5 ...
##  $ sex   : chr [1:28] "male" "female" "male" "female" ...
top_rows <- head(data_vonB, 5)    
top_rows

Visualisasi dalam bentuk Scatter plotnya adalah sebagai berikut.

library(ggplot2)
# Scatter plot awal untuk melihat distribusi data
ggplot(data_vonB, aes(x = age, y = length, color = sex)) +
  geom_point(size = 3) +
  labs(title = "Scatter Plot Panjang Ikan berdasarkan Usia dan Jenis Kelamin",
       x = "Age",
       y = "Length (cm)",
       color = "Jenis Kelamin") +
  theme_minimal()

Berdasarkan Gambar diatas, dapat didapatkan beberapa insight sebagai berikut.

  1. Ikan betina (female) cenderung memiliki pertumbuhan lebih cepat dibandingkan ikan jantan pada usia lebih lanjut.

  2. Ikan jantan (male), tampaknya mengalami perlambatan pertumbuhan setelah usia sekitar 8 tahun.

  3. Pada usia di bawah 6 tahun, panjang ikan jantan dan betina hampir sama.

  4. Setelah usia 6 tahun, ikan betina terus tumbuh lebih panjang dibandingkan ikan jantan.

  5. Jika kita kaitkan dengan budidaya ikan, ikan betina lebih besar, mungkin lebih baik membiarkan ikan betina bertumbuh lebih lama sebelum dipanen untuk produksi daging yang lebih banyak.

Kita akan melakukan estimasi parameter (\(\beta_1, \beta_2, \beta_3\)) dengan model pertumbuhan VBGM melalui 2 pendekatan, yakni:

  1. Simultan (Fitting semua parameter sekaligus [optimisasi 3D])

  2. Multi-stage Maximization dengan cara Fitting dengan Partial Linearity (optimisasi 1D): Kita menentukan \(\beta_3\) terlebih dahulu, selanjutnya menghitung \(\beta_1\) dan \(\beta_2\) dengan regresi linear.

Detailnya dari setiap pendekatan sebagai berikut.

3.1 Fitting Semua Parameter sekaligus

Gunakan fungsi nls() (Non Linear Square) ketika model tidak dapat dinyatakan dalam bentuk linear terhadap parameternya, sebagai ilustrasi

  1. Model Linear -> bisa pakai lm()

\[\begin{equation} Y=\beta_0 + \beta_1 X \end{equation}\]

  1. Model Non-Linear -> bisa Pakai nls()

\[\begin{equation} Y=\beta_0 \exp^{-\beta_1 X} \end{equation}\]

#nls: Nonlinear Least Square (nls)
vonB=data_vonB[,c(1,2)];

# Fitting model Von Bertalanffy menggunakan nls()
Snls<-nls(length~beta1-beta2*exp(-beta3*age),data=vonB,
    start=list(beta1=90,beta2=80,beta3=0.12))

# Menampilkan hasil estimasi parameter
summary(Snls)
## 
## Formula: length ~ beta1 - beta2 * exp(-beta3 * age)
## 
## Parameters:
##       Estimate Std. Error t value Pr(>|t|)    
## beta1 32.82045    3.04932  10.763 7.12e-11 ***
## beta2 23.26366    2.67473   8.698 4.95e-09 ***
## beta3  0.14427    0.04203   3.432  0.00209 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.187 on 25 degrees of freedom
## 
## Number of iterations to convergence: 4 
## Achieved convergence tolerance: 9.02e-07

3.2 Multi-Stage Maximization (Fitting dengan pendekatan Partial Linearity)

  • Kita menentukan \(\beta_3\) terlebih dahulu, selanjutnya menghitung \(\beta_1\) dan \(\beta_2\) dengan regresi linear.

  • Ketika \(\beta_3\) dianggap “tetap” pada model pertumbuhan VBGM, maka persamaan dapat direpresentasikan sebagai model regresi linear sederhana terhadap \(\beta_1\) dan \(\beta_2\). Persamaan VBGM disajikan sebagai berikut.

  • “Tetap” disini berarti \(\beta_3\) tidak diestimasi bersamaan dengan \(\beta_1\) maupun \(\beta_2\), melainkan ditentukan sebelumnya atau dioptimalkan secara terpisah.

\[\begin{equation} Y_i = \beta_1 - \beta_2 e^{- \beta_3 a_i} \\ \Leftrightarrow Y_i = a + bx_i \end{equation}\]

\(a = \beta_1\), \(b=- \beta_2\), \(x_i = e^{-\beta_3 a_i}\), \(a_i\): usia ikan.

Sintaks berikut digunakan dengan cara mengoptimalkan hanya \(\beta_3\) secara numerik, sedangkan \(\beta_1\) dan \(\beta_2\) dihitung menggunakan regresi linear.

#Taking advantage of partial linearity
Pnls<-nls(length~cbind(1,exp(-beta3*age)),data=vonB,
    start=list(beta3=0.12),algorithm="plinear") 
summary(Pnls)
## 
## Formula: length ~ cbind(1, exp(-beta3 * age))
## 
## Parameters:
##        Estimate Std. Error t value Pr(>|t|)    
## beta3   0.14427    0.04203   3.432  0.00209 ** 
## .lin1  32.82047    3.04933  10.763 7.12e-11 ***
## .lin2 -23.26368    2.67474  -8.698 4.95e-09 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.187 on 25 degrees of freedom
## 
## Number of iterations to convergence: 4 
## Achieved convergence tolerance: 9.213e-07

Penjelasan sintaks diatas

  • Nilai awal \(\beta_3\) ditetapkan sebesar \(0.12\)
  • algorithm plinear: menggunakan metode partial linearity untuk optimisasi parameter tertntu. Hanya mengoptimalkan parameter non-linear (\(\beta_3\)), sementara parameter lainnya dihitung dengan regresi linear biasa.

Berdasarkan kedua pendekatan Model regresi non linear yang dihasilkan adalah

\[\begin{equation} Y_i = \beta_1 - \beta_2 e^{-\beta_3 a_i} \\ \Leftrightarrow \hat{Y_i} = 32.82039 - 23.26368 e^{-(0.1442696 a_i}) \end{equation}\]

Berdasarkan kedua pendekatan diatas, diperoleh estimasi parameter yang disajikan pada Tabel berikut.

Tabel Hasil Estimasi Parameter
Metode \(\beta_1\) \(\beta_2\) \(\beta_3\)
Simultan (nls default) 32.82039 23.26362 0.14427
Partial (plinear) 32.82048 23.26368 0.14427

Fitting VBGM dari model yang diperoleh

# Prediksi panjang ikan menggunakan model
library(ggplot2)
data_vonB$predicted <- predict(Pnls)

# Plot hasil model
ggplot(data_vonB, aes(x = age, y = length)) +
  geom_point(aes(color = sex), size = 3) +  # Titik data asli berdasarkan jenis kelamin
  geom_line(aes(y = predicted), color = "black", size = 1) +  # Garis model prediksi
  labs(title = "Fitting Model VBGM (Partial Model)",
       x = "Age", 
       y = "Length (cm)") +
  theme_minimal()

Selanjutnya, kedua plot (simultan dan parsial) disandingkan.

library(gridExtra)

# Menyiapkan data
vonB = data_vonB[, c(1, 2)]

# Model Standard nls()
beta1 = 32.82039
beta2 = 23.26362
beta3 = 0.14427
vonB$length.duga.Snls = beta1 - beta2 * exp(-beta3 * vonB$age)

# Model dengan Partial Linearity (plinear)
beta1P = 32.82048
beta2P = 23.26368
beta3P = 0.14427
vonB$length.duga.Pnls = beta1P - beta2P * exp(-beta3P * vonB$age)

# Membuat plot pertama (nls)
plot1 <- ggplot(vonB, aes(x = age, y = length)) +
  geom_point(color = "black") +
  geom_line(aes(y = length.duga.Snls), color = "green", size = 1.2) +
  labs(title = "Model Standard nls()", x = "Age", y = "Length (cm)") +
  theme_minimal()

# Membuat plot kedua (plinear)
plot2 <- ggplot(vonB, aes(x = age, y = length)) +
  geom_point(color = "black") +
  geom_line(aes(y = length.duga.Pnls), color = "red", size = 1.2) +
  labs(title = "Model dengan Partial Linearity", x = "Age", y = "Length (cm)") +
  theme_minimal()

# Menampilkan dua plot berdampingan
grid.arrange(plot1, plot2, ncol = 2)

Berdasarkan kedua plot diatas diperoleh hasilnya yang sama, itu berarti kedua pendekatan memberikan estimasi yang sama artinya pendekatan Partial memberikan hasil yang tidak berbeda dari pendekatan Simultan pada kasus data ikan tersebut.

Sintaks partial diatas, dapat juga dipandang sebagai berikut.

# Inisialisasi parameter
beta3_init <- 0.05
tolerance <- 1e-6  
max_iter <- 100  

# Menyimpan hasil iterasi
results <- data.frame(Iterasi = numeric(), Beta1 = numeric(), Beta2 = numeric(), Beta3 = numeric(), RSS = numeric())

# Iterasi untuk optimasi
for (i in 1:max_iter) {
  # Step 1: Estimasi \beta_1 dan \beta_2 menggunakan OLS
  X <- cbind(1, exp(-beta3_init * data_vonB$age))
  Y <- data_vonB$length
  beta_1_2 <- solve(t(X) %*% X) %*% t(X) %*% Y
  
  # Step 2: Hitung prediksi dan RSS
  Y_pred <- beta_1_2[1] + beta_1_2[2] * exp(-beta3_init * data_vonB$age)
  RSS <- sum((Y - Y_pred)^2)
  
  # Step 3: Hitung turunan pertama (gradient) dan turunan kedua (hessian)
  gradient <- sum(-2 * (Y - Y_pred) * beta_1_2[2] * data_vonB$age * exp(-beta3_init * data_vonB$age))
  hessian <- sum(2 * beta_1_2[2] * data_vonB$age^2 * exp(-2 * beta3_init * data_vonB$age))
  
  beta3_new <- beta3_init - (gradient / hessian)
  
  # Simpan hasil iterasi
  results <- rbind(results, data.frame(Iterasi = i, Beta1 = beta_1_2[1], Beta2 = beta_1_2[2], Beta3 = beta3_init, RSS = RSS))
  
  # Cek konvergensi
  if (abs(beta3_new - beta3_init) < tolerance) {
    message("Konvergensi tercapai pada iterasi ke-", i)
    break
  }
  
  # Update nilai beta_3 untuk iterasi berikutnya
  beta3_init <- beta3_new
}
## Konvergensi tercapai pada iterasi ke-12
# Menampilkan hasil iterasi
print(results)
##    Iterasi    Beta1     Beta2      Beta3      RSS
## 1        1 51.79314 -40.28288 0.05000000 144.6710
## 2        2 46.57527 -35.30855 0.06094941 139.0597
## 3        3 42.26499 -31.29310 0.07441292 133.1463
## 4        4 38.79202 -28.16507 0.09052905 127.4976
## 5        5 36.12943 -25.87632 0.10855788 123.0020
## 6        6 34.28894 -24.38160 0.12589054 120.4466
## 7        7 33.26737 -23.59545 0.13813245 119.6467
## 8        8 32.89927 -23.32158 0.14314831 119.5512
## 9        9 32.82946 -23.27027 0.14414094 119.5479
## 10      10 32.82137 -23.26434 0.14425676 119.5479
## 11      11 32.82056 -23.26374 0.14426848 119.5479
## 12      12 32.82047 -23.26368 0.14426965 119.5479

Tahapan diatas meliputi:

  1. Inisialisasi
  • Tentukan nilai awal \(\beta_3\), toleransi konvergensi, dan iterasi maksimum.
  • Siapkan data frame untuk menyimpan hasil optimasi.
  1. Iterasi Maksimalisasi Looping dilakukan hingga konvergensi atau mencapai iterasi maksimum.

  2. Estimasi \(\beta_1\) dan \(\beta_2\) (OLS)

  • Buat matriks desain \(X\) dan variabel respons \(Y\).
  • Hitung parameter \(\beta_1\) dan \(\beta_2\) menggunakan metode OLS:

\[ \begin{bmatrix} \beta_1 \\ \beta_2 \end{bmatrix} = (X^T X)^{-1} X^T Y \]

  1. Hitung Prediksi dan Residual
  • Hitung prediksi panjang ikan berdasarkan \(\beta_1\) dan \(\beta_2\):

\[ Y_{\text{pred}} = \beta_1 + \beta_2 e^{-\beta_3 \cdot \text{age}} \]

  • Hitung Residual Sum of Squares (RSS):

\[ RSS = \sum (Y - Y_{\text{pred}})^2 \]

  1. Optimasi \(\beta_3\)
  • Hitung turunan pertama (gradient):

\[ \frac{d(RSS)}{d\beta_3} = \sum -2 (Y - Y_{\text{pred}}) \beta_2 \cdot \text{age} \cdot e^{-\beta_3 \cdot \text{age}} \]

  • Hitung turunan kedua (hessian):

\[ \frac{d^2(RSS)}{d\beta_3^2} = \sum 2 \beta_2 \cdot \text{age}^2 \cdot e^{-2\beta_3 \cdot \text{age}} \]

  • Perbarui \(\beta_3\) menggunakan metode Newton-Raphson:

\[ \beta_3^{(t+1)} = \beta_3^{(t)} - \frac{\frac{d(RSS)}{d\beta_3}}{\frac{d^2(RSS)}{d\beta_3^2}} \]

  1. Cek Konvergensi
  • Jika perubahan \(\beta_3\) lebih kecil dari toleransi, iterasi berhenti.
  • Jika tidak, nilai \(\beta_3\) diperbarui dan iterasi dilanjutkan.
  1. Output Hasil
  • Ditampilkan tabel hasil iterasi dan pergerakan \(\beta_3\).

4 Referensi

Millar RB. 2011. Maximum Likelihood Estimation and Inference With Examples in R, SAS and ADMB First Edition. United Kingdom: John Wiley & Sons, Ltd.

von Bertalanffy, L. (1938) A quantitative theory of organic growth, Human Biol. 10: 181–213