#Hidden Markov Model dengan Pelatihan Menggunakan Algoritma Baum-Welch Untuk Maksimasi P(O|λ) Sebagai Dasar Pencarian Urutan Hidden State Terbaik Bersyarat Observasi Berganda Oleh Algoritma Viterbi
#data asli(misal)
set.seed(121450098)
test <- sample(1:2,5,replace=T)
test
## [1] 1 1 2 2 2
transisi <- matrix(c(0.5, 0.5, 0.4, 0.6), nrow = 2, byrow = TRUE)#ini matriks transisi antra state
p0 <- c(0.6, 0.4)#probabilitas inisiasi setiap state
matrix1 <- matrix(data=c(0.2,0.7,0.1,0.1,0.7,0.2), nrow = 2, byrow = TRUE)#matriks transisi hidden state ke variabel pengamatan ke-1
matrix2 <- matrix(data=c(0.1,0.8,0.05,0.05,0.25,0.5,0.05,0.2), nrow = 2, byrow = TRUE)#matriks transisi hidden state ke variabel pengamatan ke-2
matrix3 <- matrix(data=c(0.4,0.4,0.2,0.15,0.8,0.05), nrow = 2, byrow = TRUE)#matriks transisi hidden state ke variabel pengamatan ke-3
matrix4 <- matrix(data=c(0.2,0.7,0.1,0.1,0.7,0.2),nrow = 2,byrow = T)
ems <- list(matrix1, matrix2, matrix3,matrix4)#ini bua gabungin ketiga matriks tadi supaya lebih mudah
obs <- list(c(1,4,2,1), c(3,4,1,2), c(1,4,3,2),c(2,1,2,1),c(1,1,1,1))#ini observasinya
#Observasinya ada 3, setiap observasi melakukan pengamtan terhadap 3 variabel tersebut
#Dari setiap observasi dilihat mana hidden state yang paling mungkin terjadi pada waktu itu
#Penetapan suatu state pada suatu observasi pada waktu ke-t tentunya juga memengaruhi penetapan state di waktu ke t+1. Oleh karena itu, diperlukan peninjauan terhadap urutan hidden state yang tepat dari waktu ke-1 sampai ke T(akhir). Cara melakukannya adalah dengan mencari urutan hidden state yang mampu memkasimalkan P(HiddenState_1:T | Observasi_1:T). Menggunakan cara brute force adalah salah satu cara sederhananya. Namun, beban kemangkusan menjadi taruhannya. Brute force melakuakn percobaan sebanyak observasi yakni sebanyak n_state^T. Membandingkan satu-persatu P(HiddenState_1:T | Observasi_1:T).
ems
## [[1]]
## [,1] [,2] [,3]
## [1,] 0.2 0.7 0.1
## [2,] 0.1 0.7 0.2
##
## [[2]]
## [,1] [,2] [,3] [,4]
## [1,] 0.10 0.8 0.05 0.05
## [2,] 0.25 0.5 0.05 0.20
##
## [[3]]
## [,1] [,2] [,3]
## [1,] 0.40 0.4 0.20
## [2,] 0.15 0.8 0.05
##
## [[4]]
## [,1] [,2] [,3]
## [1,] 0.2 0.7 0.1
## [2,] 0.1 0.7 0.2
viterbimultobs <- function(transisi,emisi,p0,seq_observasi){
pengamatan <- length(seq_observasi)
state <- length(p0)
deltas <- matrix(0,nrow=pengamatan,ncol=state)
psi <- matrix(0,nrow=pengamatan,ncol=state)
pmult <- function(t,obs,j,ems){
kali <- 1
for (i in 1:length(obs[[t]])) {
kali <- kali * ems[[i]][j,obs[[t]][i]]
}
return(kali)
}
for(i in 1:state){
deltas[1,i]<-pmult(1,obs,i,ems)
}
for(t in 2:pengamatan){
for(j in 1:state){
maxvector1 <- c()
for (i in 1:state) {
cekmax1 <- transisi[i,j] * deltas[t-1,i]
maxvector1<-append(maxvector1,cekmax1)
}
deltas[t,j] <- max(maxvector1)*pmult(t,seq_observasi,j,emisi)
}
}
for (t in 2:pengamatan) {
for(j in 1:state){
maxvector2<-c()
for(i in 1:state){
cekmax2 <- transisi[i,j] * deltas[t-1,i]
maxvector2 <- append(maxvector2,cekmax2)
}
psi[t,j] <- which.max(maxvector2)
}
}
qstar <- numeric(pengamatan)
qstar[pengamatan] <- which.max(deltas[pengamatan, ])
for (i in (pengamatan - 1):1) {
qstar[i] <- psi[i + 1, qstar[i + 1]]
}
return(qstar)
}
viterbimultobs(transisi, ems, p0, obs)
## [1] 2 2 1 2 1
##Forward dan Backward
forwardmultobs<- function(transisi,emisi,p0,seq_observasi) {
pengamatan <- length(seq_observasi)
state <- length(p0)
alpha<-matrix(0,pengamatan,state)
pmult <- function(t,obs,j,ems){
kali <- 1
for (i in 1:length(obs[[t]])) {
kali <- kali * ems[[i]][j,obs[[t]][i]]
}
return(kali)
}
for(i in 1:state){
alpha[1,i]<-pmult(1,obs,i,ems) * p0[i]
}
for (t in 2:pengamatan) {
for (j in 1:state) {
alpha[t,j]<-0
for (i in 1:state){
alpha[t,j] <- alpha[t,j] + transisi[i,j] * alpha[t-1,i] * pmult(t,seq_observasi,j,emisi)
}
}
}
pstar <- sum(alpha[pengamatan,])
return(list(pstar = pstar, alpha=alpha))
}
forwardmultobs(transisi,ems,p0,obs)
## $pstar
## [1] 2.996819e-14
##
## $alpha
## [,1] [,2]
## [1,] 4.800000e-04 6.400000e-04
## [2,] 6.944000e-07 2.620800e-06
## [3,] 1.953728e-09 1.343776e-09
## [4,] 8.480497e-12 2.496381e-11
## [5,] 2.276124e-14 7.206951e-15
backwardmultobs<- function(transisi,emisi,p0,seq_observasi) {
state <- length(p0)
beta <- matrix(0,length(seq_observasi),state)
beta[length(seq_observasi), ] <- 1
pmult <- function(t,obs,j,ems){
kali <- 1
for (i in 1:length(obs[[t]])) {
kali <- kali * ems[[i]][j,obs[[t]][i]]
}
return(kali)
}
for (t in (length(seq_observasi)- 1):1) {
for (i in 1:state) {
beta[t,i] <- 0
for (j in 1:state) {
beta[t, i] <- beta[t,i] + transisi[i,j] * pmult(t+1,seq_observasi,j,emisi) * beta[t + 1,j]
}
}
}
pstar <- 0
for (i in 1:state) {
pstar <- pstar + p0[i] * pmult(1, seq_observasi, i, emisi) * beta[1, i]
}
return(list(pstar = pstar, beta=beta))
}
backwardmultobs(transisi,ems,p0,obs)
## $pstar
## [1] 2.996819e-14
##
## $beta
## [,1] [,2]
## [1,] 2.537583e-11 2.779343e-11
## [2,] 9.491300e-09 8.919960e-09
## [3,] 8.820000e-06 9.478000e-06
## [4,] 9.875000e-04 8.650000e-04
## [5,] 1.000000e+00 1.000000e+00
#Fungsinya untuk melatih sampai sesuai yang diinginkan
em_pstar_with_tolerance <- function(transisi, ems, p0, seq_observasi) {
pstar <- forwardmultobs(transisi, ems, p0, seq_observasi)$pstar
pmult <- function(t,obs,j,ems){
kali <- 1
for (i in 1:length(obs[[t]])) {
kali <- kali * ems[[i]][j,obs[[t]][i]]
}
return(kali)
}
state <- length(p0)
pengamatan <- length(seq_observasi)
# simpan dulu hasil alpha dan beta selayaknya sudah menjalankan fase forward dan backward
alpha <- forwardmultobs(transisi, ems, p0, seq_observasi)$alpha
beta <- backwardmultobs(transisi, ems, p0, seq_observasi)$beta
# fase perhitungan ksi dan gamma
# mulai fase perhitungan ksi
ksi_denom <- matrix(0,nrow=pengamatan-1,ncol=1)
for (t in 1:(pengamatan - 1)) {
for (i in 1:state) {
for (j in 1:state) {
ksi_denom[t] <- ksi_denom[t] + (alpha[t, i] * transisi[i, j] * pmult(t+1,obs,j,ems) * beta[t + 1, j])
}
}
}
ksi <- array(0, dim = c(pengamatan - 1, state, state))
for (t in 1:(pengamatan - 1)) {
for (i in 1:state) {
for (j in 1:state) {
ksi[t, i, j] <- (alpha[t, i] * transisi[i, j] * pmult(t+1,obs,j,ems) * beta[t + 1, j]) / ksi_denom[t]
}
}
}
# mulai fase perhitungan gamma
gamma <- matrix(0, nrow = pengamatan, ncol = state)
for (t in 1:pengamatan) {
denom_gamma <- 0
for (i in 1:state) {
denom_gamma <- denom_gamma + (alpha[t,i ] * beta[t, i])
}
for (i in 1:state) {
gamma[t, i] <- (alpha[t, i] * beta[t, i]) / denom_gamma
}
}
# Mulai fase pembaharuan transisi, emisi, dan p0
# fase pembaharuan p0
p0_topi <- gamma[1, ]
# fase pembaharuan transisi (harus dinormalisasi tentunya)
transisi_topi <- matrix(0, nrow = state, ncol = state)
for (i in 1:state) {
denom_transisi_topi <- sum(gamma[1:pengamatan-1, i])
for (j in 1:state) {
for (t in 1:(pengamatan - 1)) {
transisi_topi[i, j] <- transisi_topi[i, j] + (ksi[t, i, j] / denom_transisi_topi)
}
}
}
for (i in 1:state) { # normalisasi dulu
normalize_markov <- sum(transisi_topi[i, ])
for (j in 1:state) {
transisi_topi[i, j] <- transisi_topi[i, j] / normalize_markov
}
}
# fase pembaharuan emisi
delta <- function(t,k,v,seq_observasi) { # fungsi delta, kalau observasi ke-t != k maka akan return 0
if (seq_observasi[[t]][k] == v) {
return(1)
} else {
return(0)
}
}
normalize <- function(matriks) {
for (i in 1:nrow(matriks)) {
denom_normalize <- sum(matriks[i, ])
if (denom_normalize > 0) {
matriks[i, ] <- matriks[i, ] / denom_normalize
}
}
return(matriks)
}
dimensi <- length(seq_observasi[[1]])
list_emisi <- vector("list", dimensi)
for (k in 1:dimensi) {
emisi_topi <- matrix(0, nrow = state, ncol = ncol(ems[[k]]))
for (j in 1:state) {
denom_emisi_topi <- sum(gamma[, j])
for (v in 1:ncol(ems[[k]])) {
for (t in 1:pengamatan) {
emisi_topi[j, v] <- emisi_topi[j, v] + (gamma[t, j] * delta(t,k,v,seq_observasi)) / denom_emisi_topi
}
}
}
list_emisi[[k]] <- normalize(emisi_topi)
}
#untuk hitung pstar baru
pstar_topi <- forwardmultobs(transisi_topi,list_emisi,p0_topi,seq_observasi)$pstar
return(list(p0_new = p0_topi,
emisi_new = list_emisi,
transisi_new = transisi_topi,
pstar_topi = pstar_topi))
}
result<-em_pstar_with_tolerance(transisi,ems,p0,obs)#memunculkan parameter yang sudah dilatih dan pstar yang meningkat
afterEM <- viterbimultobs(result$transisi_new,result$emisi_new,result$p0_new,obs)
cat("Setelah EM urutannya :",afterEM)#kasus ini sama kebetulan baik sebelum dengan sesudah
## Setelah EM urutannya : 2 2 1 2 1
print("Hasil sesudah EM")
## [1] "Hasil sesudah EM"
result#setelah pelatihan(di dalamnya mencakup pstar dan juga parameter yang dilatih)
## $p0_new
## [1] 0.4064442 0.5935558
##
## $emisi_new
## $emisi_new[[1]]
## [,1] [,2] [,3]
## [1,] 0.7770997 0.1247341 0.09816622
## [2,] 0.4562280 0.2611019 0.28267006
##
## $emisi_new[[2]]
## [,1] [,2] [,3] [,4]
## [1,] 0.4637519 0 0 0.5362481
## [2,] 0.3482453 0 0 0.6517547
##
## $emisi_new[[3]]
## [,1] [,2] [,3]
## [1,] 0.4371841 0.3061553 0.2566607
## [2,] 0.3698135 0.4761844 0.1540021
##
## $emisi_new[[4]]
## [,1] [,2] [,3]
## [1,] 0.6451731 0.3548269 0
## [2,] 0.5633279 0.4366721 0
##
##
## $transisi_new
## [,1] [,2]
## [1,] 0.4430792 0.5569208
## [2,] 0.4675211 0.5324789
##
## $pstar_topi
## [1] 8.559356e-10
print("Hasil sebelum EM")
## [1] "Hasil sebelum EM"
forwardmultobs(transisi,ems,p0,obs)$pstar
## [1] 2.996819e-14
list(transisi,ems,p0)#sebelum pelatihan
## [[1]]
## [,1] [,2]
## [1,] 0.5 0.5
## [2,] 0.4 0.6
##
## [[2]]
## [[2]][[1]]
## [,1] [,2] [,3]
## [1,] 0.2 0.7 0.1
## [2,] 0.1 0.7 0.2
##
## [[2]][[2]]
## [,1] [,2] [,3] [,4]
## [1,] 0.10 0.8 0.05 0.05
## [2,] 0.25 0.5 0.05 0.20
##
## [[2]][[3]]
## [,1] [,2] [,3]
## [1,] 0.40 0.4 0.20
## [2,] 0.15 0.8 0.05
##
## [[2]][[4]]
## [,1] [,2] [,3]
## [1,] 0.2 0.7 0.1
## [2,] 0.1 0.7 0.2
##
##
## [[3]]
## [1] 0.6 0.4