Giả sử số vụ tràn dầu \(N_i\) trong năm thứ \(i\) tuân theo phân phối Poisson với tham số \(\lambda_i\):
\[ N_i \mid b_{i1}, b_{i2} \sim \text{Poisson}(\lambda_i) \]
Trong đó:
\[ \lambda_i = \alpha_1 b_{i1} + \alpha_2 b_{i2} \]
Hàm likelihood của mô hình Poisson là:
\[ L(\alpha_1, \alpha_2) = \prod_{i=1}^{n} \frac{e^{-\lambda_i} \lambda_i^{N_i}}{N_i!} \]
Hàm log-likelihood là:
\[ \ell(\alpha_1, \alpha_2) = \sum_{i=1}^{n} \left[ N_i \log(\lambda_i) - \lambda_i - \log(N_i!) \right] \]
Thay \(\lambda_i = \alpha_1 b_{i1} + \alpha_2 b_{i2}\), ta có:
\[ \ell(\alpha_1, \alpha_2) = \sum_{i=1}^{n} \left[ N_i \log\left(\alpha_1 b_{i1} + \alpha_2 b_{i2}\right) - \left(\alpha_1 b_{i1} + \alpha_2 b_{i2}\right) - \log(N_i!) \right] \]
Các bước giải thuật 1. Khởi tạo: - Chọn giá trị ban đầu: \[ \alpha^{(0)} = \bigl(\alpha_1^{(0)},\, \alpha_2^{(0)}\bigr) \]
Tính gradient và Hessian:
Đạo hàm theo \(\alpha_1\): \[ \frac{\partial \ell}{\partial \alpha_1} = \sum_{i=1}^{n} b_{i1}\left(\frac{N_i}{\lambda_i} - 1\right). \]
Đạo hàm theo \(\alpha_2\): \[ \frac{\partial \ell}{\partial \alpha_2} = \sum_{i=1}^{n} b_{i2}\left(\frac{N_i}{\lambda_i} - 1\right). \]
Vậy vector gradient là: \[ \nabla \ell(\alpha_1, \alpha_2) = \begin{pmatrix} \displaystyle \sum_{i=1}^{n} b_{i1}\left(\frac{N_i}{\lambda_i} - 1\right) \\ \\ \displaystyle \sum_{i=1}^{n} b_{i2}\left(\frac{N_i}{\lambda_i} - 1\right) \end{pmatrix}. \]
Đạo hàm riêng cấp 2 theo \(\alpha_1\): \[ \frac{\partial^2 \ell}{\partial \alpha_1^2} = -\sum_{i=1}^{n} \frac{N_i \, b_{i1}^2}{\lambda_i^2}. \]
Đạo hàm riêng cấp 2 theo \(\alpha_2\): \[ \frac{\partial^2 \ell}{\partial \alpha_2^2} = -\sum_{i=1}^{n} \frac{N_i \, b_{i2}^2}{\lambda_i^2}. \]
Đạo hàm hỗn hợp theo \(\alpha_1\) và \(\alpha_2\): \[
\frac{\partial^2 \ell}{\partial \alpha_1 \partial \alpha_2} =
-\sum_{i=1}^{n} \frac{N_i \, b_{i1} b_{i2}}{\lambda_i^2}.
\]
=> Do đó, ma trận Hessian của hàm log-likelihood là: \[
H(\alpha_1, \alpha_2) =
\begin{pmatrix}
-\displaystyle \sum_{i=1}^{n} \frac{N_i \, b_{i1}^2}{\lambda_i^2} &
-\displaystyle \sum_{i=1}^{n} \frac{N_i \, b_{i1} b_{i2}}{\lambda_i^2}
\\[2mm]
-\displaystyle \sum_{i=1}^{n} \frac{N_i \, b_{i1} b_{i2}}{\lambda_i^2}
& -\displaystyle \sum_{i=1}^{n} \frac{N_i \, b_{i2}^2}{\lambda_i^2}
\end{pmatrix}.
\]
Cập nhật tham số: \[ \alpha^{(k+1)} = \alpha^{(k)} - H^{-1}\bigl(\alpha^{(k)}\bigr) \, \nabla \ell\bigl(\alpha^{(k)}\bigr) \]
Kiểm tra điều kiện dừng:
Chương trình thi hành giải thuật
#Đọc dữ liệu
data <- read.table("/Users/kieuhoa.vo/Downloads/0. Study/Master/MTT018 - Thong ke tinh toan/Assignment/Bai tap 1/oilspills.dat", header = TRUE)
spills <- data$spills
importexport <- data$importexport
domestic <- data$domestic
#Hàm log-likelihood
log_likelihood <- function(alpha, spills, importexport, domestic)
{
lambda <- alpha[1] * importexport + alpha[2] * domestic
l_likelihood <- sum(-lambda + spills * log(lambda) - log(factorial(spills)))
return (l_likelihood)
}
#Tính đạo hàm
gradient <- function(alpha, splills, importexport, domestic)
{
lambda <- alpha[1] * importexport + alpha[2] * domestic
d_alpha1 <- sum(-importexport + (splills*importexport)/lambda)
d_alpha2 <- sum(-domestic + (splills*domestic)/lambda)
return(c(d_alpha1, d_alpha2))
}
#Tính Hessian matrix
hessian <- function(alpha, splills, importexport, domestic)
{
lambda <- alpha[1] * importexport + alpha[2] * domestic
h11 <- sum( (-importexport^2 *splills) / lambda^2)
h22 <- sum( (-domestic^2 *splills) / lambda^2)
h12 <- sum( (-spills *importexport *domestic)/lambda^2 ) #đạo hàm hỗn hợp
return(matrix(c(h11, h12, h12, h22), nrow = 2, byrow = TRUE))
}
newton <- function(alpha_init, spills, importexport, domestic, tolerance = 1e-6, max_iter = 150)
{
alpha <- alpha_init
path <- matrix(alpha, nrow = 1) # Khởi tạo đường đi với điểm ban đầu
for (i in 1:max_iter)
{
grad <- gradient(alpha, spills, importexport, domestic)
hess <- hessian(alpha, spills, importexport, domestic)
if (det(hess) != 0)
{
alpha_new <- alpha - solve(hess) %*% grad
path <- rbind(path, t(alpha_new)) # Lưu giá trị mới vào đường đi
if (max(abs(alpha_new - alpha )) < tolerance)
{
#print(cat("Break at irr: ", i ))
break
}
alpha <- alpha_new
}
}
return(list(alpha = alpha, path = path))
}
#Ước lượng MLE bằng pp newton
alpha_init_nt <- c(0.7, 0.7)
result <- newton(alpha_init_nt, spills, importexport, domestic)
alpha_estimated_nt <- result$alpha
newton_path <- result$path
print(cat("Kết quả Ước lượng MLE bằng pp newton","alpha1 = ",alpha_estimated_nt[1], ",alpha2 = ", alpha_estimated_nt[2], "\n"))
## Kết quả Ước lượng MLE bằng pp newton alpha1 = 1.097152 ,alpha2 = 0.9375546
## NULL
Các bước giải thuật:
1.Khởi tạo Chọn giá trị ban đầu: \[ \alpha^{(0)} = \bigl(\alpha_1^{(0)},\, \alpha_2^{(0)}\bigr). \]
2: Tính gradient và Fisher Information
Tính gradient: \[ \nabla \ell\bigl(\alpha^{(k)}\bigr) = \begin{pmatrix} \displaystyle \frac{\partial \ell}{\partial \alpha_1} \\[1mm] \displaystyle \frac{\partial \ell}{\partial \alpha_2} \end{pmatrix}. \]
Tính Fisher Information: \[ I\bigl(\alpha^{(k)}\bigr) = \begin{pmatrix} \displaystyle \sum_{i=1}^{n} \frac{b_{i1}^2}{\lambda_i} & \displaystyle \sum_{i=1}^{n} \frac{b_{i1}b_{i2}}{\lambda_i} \\[2mm] \displaystyle \sum_{i=1}^{n} \frac{b_{i1}b_{i2}}{\lambda_i} & \displaystyle \sum_{i=1}^{n} \frac{b_{i2}^2}{\lambda_i} \end{pmatrix}. \]
3: Cập nhật tham số
Cập nhật tham số theo công thức: \[
\alpha^{(k+1)} = \alpha^{(k)} + I^{-1}\bigl(\alpha^{(k)}\bigr)\, \nabla
\ell\bigl(\alpha^{(k)}\bigr).
\]
4: Kiểm tra điều kiện dừng
Nếu \[
\|\alpha^{(k+1)} - \alpha^{(k)}\| < \epsilon,
\]
với \(\epsilon\) là ngưỡng nhỏ ( \(10^{-6}\)), dừng lại. Ngược lại, quay lại
Bước 2.
Chương trình thi hành giải thuật
#Tính fisher information matrix
fisher_information <- function(alpha, importexport, domestic)
{
lambda <- alpha[1] * importexport + alpha[2] * domestic
i11 <- sum((importexport^2)/lambda)
i22 <- sum((domestic^2)/lambda)
i12 <- sum((importexport*domestic)/lambda)
return(matrix(c(i11, i12, i12, i22), nrow = 2, byrow = TRUE))
}
#Phương pháp Fisher Scoring
fisher_scoring <- function (alpha_init, spills, importexport, domestic, tol = 1e-6, max_iter = 150)
{
alpha <- alpha_init
path <- matrix(alpha, nrow = 1)
for (i in 1:max_iter)
{
# Tính gradient
grad <- gradient(alpha, spills, importexport, domestic)
# Tính Fisher Information
fisher_info <- fisher_information(alpha, importexport, domestic)
# Cập nhật tham số
alpha_new <- alpha + solve(fisher_info) %*% grad
path <- rbind(path, t(alpha_new)) # Lưu giá trị mới vào đường đi
# Kiểm tra điều kiện dừng
if (max(abs(alpha_new - alpha)) < tol) {
break
}
alpha <- alpha_new
}
return(list(alpha = alpha, path = path))
}
# Ước lượng MLE bằng Fisher Scoring
alpha_init_Fisher <- c(0.7, 0.7)
result <- fisher_scoring(alpha_init_Fisher, spills, importexport, domestic)
alpha_mle_fisher <- result$alpha
fisher_path <- result$path
print(cat("Kết quả ướclượng MLE bằng Fisher Scoring","alpha1 = ",alpha_mle_fisher[1], ",alpha2 = ", alpha_mle_fisher[2], "\n"))
## Kết quả ướclượng MLE bằng Fisher Scoring alpha1 = 1.097153 ,alpha2 = 0.9375543
## NULL
Sai số chuẩn của các ước lượng MLE \(\alpha_1\) và \(\alpha_2\) được tính bằng căn bậc hai của các phần tử trên đường chéo chính của ma trận nghịch đảo Fisher:
\[ SE(\alpha_1) = \sqrt{[I^{-1}(\alpha)]_{11}}, \]
\[ SE(\alpha_2) = \sqrt{[I^{-1}(\alpha)]_{22}}. \]
# Ước lượng sai số chuẩn
standard_errors <- function(alpha, importexport, domestic)
{
# Tính ma trận thông tin Fisher
fisher_info <- fisher_information(alpha, importexport, domestic)
# Tính ma trận nghịch đảo của Fisher Information
inv_fisher_info <- solve(fisher_info)
# Tính sai số chuẩn
se_alpha1 <- sqrt(inv_fisher_info[1, 1])
se_alpha2 <- sqrt(inv_fisher_info[2, 2])
return(c(se_alpha1, se_alpha2))
}
#Sử dụng ước lượng MLE từ câu c
standard_err <- standard_errors(alpha_mle_fisher, importexport, domestic)
print(cat("Ước ượng sai số chuẩn (standard errors) của ước lượng MLE","se_alpha1 = ",standard_err[1], ",se_alpha2 = ", standard_err[2], "\n"))
## Ước ượng sai số chuẩn (standard errors) của ước lượng MLE se_alpha1 = 0.437556 ,se_alpha2 = 0.6314687
## NULL
Phương pháp quasi-Newton cập nhật tham số:
\[ \alpha^{(k+1)} = \alpha^{(k)} - \eta_k \, M^{(k)} \, \nabla \ell\bigl(\alpha^{(k)}\bigr) \]
Trong đó: - \(\eta_k\) : Bước học (learning rate) tại lần lặp thứ \(k\). - \(M^{(k)}\) : Xấp xỉ của ma trận nghịch đảo Hessian tại lần lặp thứ \(k\). - \(\nabla \ell\bigl(\alpha^{(k)}\bigr)\) : Gradient của hàm log-likelihood tại \(\alpha^{(k)}\).
Cập nhật ma trận \(M^{(k)}\) theo công thức BFGS:
\[ M^{(k+1)} = M^{(k)} + \frac{\left(s^{(k)} - M^{(k)} y^{(k)}\right)\left(s^{(k)} - M^{(k)} y^{(k)}\right)^T}{\left(s^{(k)} - M^{(k)} y^{(k)}\right)^T y^{(k)}} \]
với:
\[ s^{(k)} = \alpha^{(k+1)} - \alpha^{(k)} \]
# Phương pháp quasi-Newton
quasi_newton <- function(alpha_init, spills, importexport, domestic, M_init, tol = 1e-6, max_iter = 100)
{
alpha <- alpha_init
path <- matrix(alpha, nrow = 1)
M <- M_init
for (i in 1:max_iter) {
grad <- gradient(alpha, spills, importexport, domestic)
alpha_new <- alpha - M %*% grad
path <- rbind(path, t(alpha_new)) # Lưu giá trị mới vào đường đi
s <- alpha_new - alpha
y <- gradient(alpha_new, spills, importexport, domestic) - grad
M <- M + (s - M %*% y) %*% t(s - M %*% y) / as.numeric(t(s - M %*% y) %*% y)
if (max(abs(alpha_new - alpha)) < tol)
{
break
}
alpha <- alpha_new
}
return(list(alpha = alpha,path = path ) )
}
alpha_init_quasi <- c(1, 1)
# Cách 1: Ma trận đơn vị âm
M_init_1 <- -diag(2)
cat("Thời gian chạy với ma trận đơn vị âm:\n")
## Thời gian chạy với ma trận đơn vị âm:
time_1 <- round(system.time({
alpha_mle_1 <- quasi_newton(alpha_init_quasi, spills, importexport, domestic, M_init_1)
}), 12)
cat("Ước lượng MLE với ma trận đơn vị âm:")
## Ước lượng MLE với ma trận đơn vị âm:
print(alpha_mle_1$alpha)
## [,1]
## [1,] 1.0971525
## [2,] 0.9375546
print(time_1)
## user system elapsed
## 0.005 0.000 0.005
# Cách 2: Ma trận thông tin Fisher
fisher_info <- fisher_information(alpha_init_quasi, importexport, domestic)
M_init_2 <- -solve(fisher_info)
cat("Thời gian chạy với ma trận thông tin Fisher:\n")
## Thời gian chạy với ma trận thông tin Fisher:
time_2 <- round(system.time({
alpha_mle_2 <- quasi_newton(alpha_init_quasi, spills, importexport, domestic, M_init_2)
}), 12)
cat("Ước lượng MLE với ma trận thông tin Fisher:")
## Ước lượng MLE với ma trận thông tin Fisher:
print(alpha_mle_2$alpha)
## [,1]
## [1,] 1.0971525
## [2,] 0.9375547
print(time_2)
## user system elapsed
## 0 0 0
# So sánh thời gian chạy
cat("So sánh thời gian chạy:\n")
## So sánh thời gian chạy:
cat("Ma trận đơn vị âm:", time_1["elapsed"], "giây\n")
## Ma trận đơn vị âm: 0.005 giây
cat("Ma trận thông tin Fisher:", time_2["elapsed"], "giây\n")
## Ma trận thông tin Fisher: 0 giây
cat("So sánh số vòng lặp:\n")
## So sánh số vòng lặp:
cat("Ma trận đơn vị âm:", length(alpha_mle_1$path[,1]), "vòng lặp\n")
## Ma trận đơn vị âm: 10 vòng lặp
cat("Ma trận thông tin Fisher:", length(alpha_mle_2$path[,2]), "vòng lặp\n")
## Ma trận thông tin Fisher: 6 vòng lặp
Kết luận so sánh:
Ma trận đơn vị âm hội tụ chậm hơn, đặc biệt khi giá trị ban đầu xa giá trị tối ưu. Cách này có thể ổn định hơn khi giá trị ban đầu gần với giá trị tối ưu.
Ma trận thông tin Fisher: Hội tụ nhanh hơn vì nó cung cấp một xấp xỉ tốt hơn cho Hessian, tuy nhiên có thể không ổn định nếu Fisher information matrix không được tính chính xác.
# Tạo lưới giá trị cho alpha1 và alpha2
alpha1 <- seq(0.5, 2, length.out = 100)
alpha2 <- seq(0.5, 2, length.out = 100)
loglik_mat <- matrix(NA, nrow = length(alpha1), ncol = length(alpha2))
# Tính giá trị log-likelihood cho mỗi điểm trên lưới
for (i in 1:length(alpha1)) {
for (j in 1:length(alpha2))
{
loglik_mat[i, j] <- log_likelihood(c(alpha1[i], alpha2[j]), spills, importexport, domestic)
}
}
# Vẽ đồ thị contour
contour(
x = alpha1,
y = alpha2,
z = loglik_mat,
xlab = "α₁",
ylab = "α₂",
main = "Contour của Log-Likelihood Function",
nlevels = 100 # Số đường đồng mức
)
# Thêm đường đi của Newton Method
lines(newton_path[, 1], newton_path[, 2], col = "red", lwd = 1, lty = 1)
# Thêm điểm bắt đầu và kết thúc
points(alpha_init_nt[1], alpha_init_nt[2], col = "black", pch = 16, cex = 1) # Điểm bắt đầu
points(alpha_estimated_nt[1], alpha_estimated_nt[2], col = "blue", pch = 16, cex = 0.7) # Điểm kết thúc
#-----------------
# Thêm đường đi của Fisher scoring
lines(fisher_path[, 1], fisher_path[, 2], col = "green", lwd = 1, lty = 1)
# Thêm điểm bắt đầu và kết thúc
points(alpha_init_Fisher[1], alpha_init_Fisher[2], col = "black", pch = 16, cex = 0.7) # Điểm bắt đầu
points(alpha_mle_fisher[1], alpha_mle_fisher[2], col = "blue", pch = 4, cex = 1) # Điểm kết thúc
#-----------------
# Thêm đường đi của quasi-Newton
path_quasi <- alpha_mle_2$path
lines(path_quasi[, 1], path_quasi[, 2], col = "blue", lwd = 1, lty = 1)
# Thêm điểm bắt đầu và kết thúc
points(alpha_init_quasi[1], alpha_init_quasi[2], col = "black", pch = 16, cex = 0.7) # Điểm bắt đầu
points(alpha_mle_2$alpha[1], alpha_mle_2$alpha[2], col = "red", pch = 16, cex = 0.7) # Điểm kết thúc
Trong đó: