You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用R语言HMM包时baumWelch函数报错:缺失TRUE/FALSE所需值

解决HMM包baumWelch函数迭代时报错问题

问题重现

使用R语言的HMM包构建含4个隐状态的模型,观测值范围为2-15,初始化过程无异常,但运行baumWelch函数时,当迭代次数设置为100(或较大值)时出现如下报错:

Error in if (d < delta) { : missing value where TRUE/FALSE needed.

减少迭代次数到10时可正常运行,但迭代次数不足无法让模型收敛,即使使用默认的delta=1e-9仍会报错。

初始化代码如下:

if (!require(HMM, quietly = TRUE)) {
  install.packages("HMM")
  library(HMM)
} else {
  library(HMM)
}

# Load data
url <- "https://raw.githubusercontent.com/luancvieira/HMM/main/ottawa_2010-2012.csv"
df <- read.csv(url)

observed_data <- df$AvgTemperature

# Define number and names of states
n_states <- 4
state_names <- paste0("State", 1:n_states)

# Sorting symbols
symbol_names <- as.character(sort(unique(observed_data)))
observed_data <- as.character(observed_data)

# Initialize the HMM model with random probabilities
start_probs <- runif(n_states)
trans_probs <- matrix(runif(n_states * n_states),
               nrow = n_states, ncol = n_states)
emission_probs <- matrix(runif(n_states * length(symbol_names)), 
                  nrow = n_states, ncol = length(symbol_names))

# Normalize rows to ensure probabilities sum to 1
start_probs <- start_probs / sum(start_probs)
trans_probs <- trans_probs / rowSums(trans_probs)
emission_probs <- emission_probs / rowSums(emission_probs)

# Initialize the HMM model
hmm_model <- initHMM(States = state_names,
                     Symbols = symbol_names,
                     startProbs = start_probs,
                     transProbs = trans_probs,
                     emissionProbs = emission_probs)

# Print the initialized model
print(hmm_model)

报错的baumWelch调用代码:

bw = baumWelch(hmm = hmm_model,observation = observed_data,
               maxIterations = 100, delta = 0.001)

报错原因

该错误本质是迭代过程中计算的对数似然差值d出现了NA值,通常由以下原因导致:

  • 数值下溢:随机初始化的概率矩阵可能出现极小值,后续计算中多次相乘后数值趋近于0,取对数时产生NaN。
  • 极端初始参数:完全随机的初始概率可能导致模型在迭代中陷入不稳定状态,似然值计算出现异常。
  • 零概率问题:发射或转移矩阵中存在0概率值,计算log概率时直接产生-Inf,最终导致差值计算出现NA。

解决方案

1. 带平滑的参数初始化

在初始化概率矩阵时,给每个元素添加极小的平滑项(如1e-8),避免出现0概率,同时保证归一化后概率和为1:

# 带平滑的初始概率初始化
epsilon <- 1e-8

start_probs <- runif(n_states) + epsilon
start_probs <- start_probs / sum(start_probs)

trans_probs <- matrix(runif(n_states * n_states) + epsilon,
                      nrow = n_states, ncol = n_states)
trans_probs <- trans_probs / rowSums(trans_probs)

emission_probs <- matrix(runif(n_states * length(symbol_names)) + epsilon, 
                         nrow = n_states, ncol = length(symbol_names))
emission_probs <- emission_probs / rowSums(emission_probs)

2. 基于数据分布初始化发射概率

完全随机的发射概率可能偏离数据真实分布,可基于观测数据的分位数分组来初始化,让初始参数更合理:

# 基于观测数据分位数初始化发射概率
# 将观测值按4个分位数分组(对应4个状态)
observed_numeric <- as.numeric(observed_data)
quantiles <- quantile(observed_numeric, probs = seq(0, 1, length.out = n_states + 1))

emission_probs <- matrix(0, nrow = n_states, ncol = length(symbol_names))
for (i in 1:n_states) {
  # 找到当前状态对应的观测值范围
  lower <- quantiles[i]
  upper <- quantiles[i+1]
  # 计算该范围内每个观测值的频率
  mask <- observed_numeric >= lower & observed_numeric <= upper
  freq <- table(observed_numeric[mask])
  # 将频率映射到symbol_names的位置
  for (sym in names(freq)) {
    col_idx <- which(symbol_names == sym)
    emission_probs[i, col_idx] <- freq[sym]
  }
  # 添加平滑项并归一化
  emission_probs[i, ] <- emission_probs[i, ] + epsilon
  emission_probs[i, ] <- emission_probs[i, ] / sum(emission_probs[i, ])
}

3. 分阶段迭代

先运行少量迭代得到相对稳定的模型,再以此为初始值继续迭代,避免一次性迭代过多步出现数值异常:

# 第一阶段:少量迭代得到稳定模型
bw_stage1 <- baumWelch(hmm = hmm_model, observation = observed_data,
                       maxIterations = 20, delta = 0.001)

# 第二阶段:用第一阶段的结果继续迭代
bw_final <- baumWelch(hmm = bw_stage1$hmm, observation = observed_data,
                      maxIterations = 80, delta = 0.001)

4. 跟踪迭代过程

开启trace=TRUE参数,查看每一步的似然值变化,定位异常出现的迭代步骤:

bw = baumWelch(hmm = hmm_model, observation = observed_data,
               maxIterations = 100, delta = 0.001, trace = TRUE)

修改后的完整示例代码

if (!require(HMM, quietly = TRUE)) {
  install.packages("HMM")
  library(HMM)
} else {
  library(HMM)
}

# Load data
url <- "https://raw.githubusercontent.com/luancvieira/HMM/main/ottawa_2010-2012.csv"
df <- read.csv(url)

observed_data <- df$AvgTemperature
observed_numeric <- as.numeric(observed_data)

# Define number and names of states
n_states <- 4
state_names <- paste0("State", 1:n_states)

# Sorting symbols
symbol_names <- as.character(sort(unique(observed_data)))
observed_data <- as.character(observed_data)

# 初始化参数:带平滑+基于数据的发射概率
epsilon <- 1e-8

# 初始状态概率
start_probs <- runif(n_states) + epsilon
start_probs <- start_probs / sum(start_probs)

# 转移概率矩阵
trans_probs <- matrix(runif(n_states * n_states) + epsilon,
                      nrow = n_states, ncol = n_states)
trans_probs <- trans_probs / rowSums(trans_probs)

# 基于分位数的发射概率初始化
quantiles <- quantile(observed_numeric, probs = seq(0, 1, length.out = n_states + 1))
emission_probs <- matrix(epsilon, nrow = n_states, ncol = length(symbol_names))

for (i in 1:n_states) {
  lower <- quantiles[i]
  upper <- quantiles[i+1]
  mask <- observed_numeric >= lower & observed_numeric <= upper
  freq <- table(observed_numeric[mask])
  
  for (sym in names(freq)) {
    col_idx <- which(symbol_names == sym)
    emission_probs[i, col_idx] <- freq[sym] + epsilon
  }
  
  emission_probs[i, ] <- emission_probs[i, ] / sum(emission_probs[i, ])
}

# 初始化HMM模型
hmm_model <- initHMM(States = state_names,
                     Symbols = symbol_names,
                     startProbs = start_probs,
                     transProbs = trans_probs,
                     emissionProbs = emission_probs)

# 分阶段迭代
bw_stage1 <- baumWelch(hmm = hmm_model, observation = observed_data,
                       maxIterations = 20, delta = 0.001)
bw_final <- baumWelch(hmm = bw_stage1$hmm, observation = observed_data,
                      maxIterations = 80, delta = 0.001, trace = TRUE)

# 查看最终模型
print(bw_final$hmm)

内容的提问来源于stack exchange,提问作者Luan Vieira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 12:13:18