Viterbi算法实战案例(天气变化、词性预测)
标签: Viterbi算法实战案例(天气变化、词性预测) 博客 51CTO博客
2023-05-05 18:24:08 294浏览
Viterbi算法实战案例(天气变化、词性预测),Viterbi算法实战案例(天气预测、词性预测)人类活动与天气的预测单词词性的预测Viterbi算法图解笔记人类活动与天气的预测案例Viterbi.java的代码:packagecom.hankcs.book.ch01;/***维特比算法*@authorhankcs*/publicclassViterbi{/**...
Viterbi算法实战案例(天气预测、词性预测)
前置知识:
- 时间复杂度、递归算法、动态规划算法
- 贝叶斯公式、条件概率、联合概率
- NLP自然语言处理
本文讲解内容:
- 天气变化的案例(代码):给定三个矩阵参数π、A、B。π是第一天为晴天、雨天的概率;A是晴天、雨天相互转换的状态矩阵,B是晴天雨天状态与活动(散步、购物、打扫卫生)的转移概率矩阵。 如果某人三天的活动分别是散步、购物、打扫卫生,问:这三天的天气怎么样?(下雨还是晴天))
- 单词词性的预测案例(代码):使用维特比算法预测词性。
- Viterbi算法图解笔记
天气变化的案例的笔记如下:



天气变化的案例
Viterbi.java的代码:
package com.hankcs.book.ch01;
/**
* 维特比算法
* @author hankcs
*/
public class Viterbi
{
/**
* 求解HMM模型
* @param obs 观测序列
* @param states 隐状态
* @param start_p 初始概率(隐状态)
* @param trans_p 转移概率(隐状态)
* @param emit_p 发射概率 (隐状态表现为显状态的概率)
* @return 最可能的序列
*/
public static int[] compute(int[] obs, int[] states, double[] start_p, double[][] trans_p, double[][] emit_p)
{
double[][] V = new double[obs.length][states.length];
int[][] path = new int[states.length][obs.length];
for (int y : states)
{
V[0][y] = start_p[y] * emit_p[y][obs[0]];
path[y][0] = y;
}
for (int t = 1; t < obs.length; ++t)
{
int[][] newpath = new int[states.length][obs.length];
for (int y : states)
{
double prob = -1;
int state;
for (int y0 : states)
{
double nprob = V[t - 1][y0] * trans_p[y0][y] * emit_p[y][obs[t]];
if (nprob > prob)
{
prob = nprob;
state = y0;
// 记录最大概率
V[t][y] = prob;
// 记录路径
System.arraycopy(path[state], 0, newpath[y], 0, t);
newpath[y][t] = y;
}
}
}
path = newpath;
}
double prob = -1;
int state = 0;
for (int y : states)
{
if (V[obs.length - 1][y] > prob)
{
prob = V[obs.length - 1][y];
state = y;
}
}
return path[state];
}
}
WeatherExample.java的代码:
package com.hankcs.book.ch01;
import static com.hankcs.book.ch01.WeatherExample.Weather.*;
import static com.hankcs.book.ch01.WeatherExample.Activity.*;
public class WeatherExample
{
enum Weather
{
Rainy,
Sunny,
}
enum Activity
{
walk,
shop,
clean,
}
static int[] states = new int[]{Rainy.ordinal(), Sunny.ordinal()};
static int[] observations = new int[]{walk.ordinal(), shop.ordinal(), clean.ordinal(), shop.ordinal(), walk.ordinal()};
static double[] start_probability = new double[]{0.6, 0.4};
static double[][] transititon_probability = new double[][]{
{0.7, 0.3},
{0.4, 0.6},
};
static double[][] emission_probability = new double[][]{
{0.1, 0.4, 0.5},
{0.6, 0.3, 0.1},
};
public static void main(String[] args)
{
int[] result = Viterbi.compute(observations, states, start_probability, transititon_probability, emission_probability);
for (int r : result)
{
System.out.print(Weather.values()[r] + " ");
}
System.out.println();
}
}
运行结果如下:
Sunny Rainy Rainy Rainy Sunny
词性预测案例
#!/usr/bin/env python
# coding: utf-8
# In[1]:
tag2id, id2tag = {}, {} # maps tag to id . tag2id: {"VB": 0, "NNP":1,..} , id2tag: {0: "VB", 1: "NNP"....}
word2id, id2word = {}, {} # maps word to id
for line in open('traindata.txt'):
items = line.split('/')
word, tag = items[0], items[1].rstrip() # 抽取每一行里的单词和词性
if word not in word2id:
word2id[word] = len(word2id)
id2word[len(id2word)] = word
if tag not in tag2id:
tag2id[tag] = len(tag2id)
id2tag[len(id2tag)] = tag
M = len(word2id) # M: 词典的大小、# of words in dictionary
N = len(tag2id) # N: 词性的种类个数 # of tags in tag set
# In[2]:
# 构建 pi, A, B
import numpy as np
pi = np.zeros(N) # 每个词性出现在句子中第一个位置的概率, N: # of tags pi[i]: tag i出现在句子中第一个位置的概率
A = np.zeros((N, M)) # A[i][j]: 给定tag i, 出现单词j的概率。 N: # of tags M: # of words in dictionary
B = np.zeros((N,N)) # B[i][j]: 之前的状态是i, 之后转换成转态j的概率 N: # of tags
# In[3]:
prev_tag = ""
for line in open('traindata.txt'):
items = line.split('/')
wordId, tagId = word2id[items[0]], tag2id[items[1].rstrip()]
if prev_tag == "": # 这意味着是句子的开始
pi[tagId] += 1
A[tagId][wordId] += 1
else: # 如果不是句子的开头
A[tagId][wordId] += 1
B[tag2id[prev_tag]][tagId] += 1
if items[0] == ".":
prev_tag = ""
else:
prev_tag = items[1].rstrip()
# normalize
pi = pi/sum(pi)
for i in range(N):
A[i] /= sum(A[i])
B[i] /= sum(B[i])
# 到此为止计算完了模型的所有的参数: pi, A, B
# In[4]:
def log(v):
if v == 0:
return np.log(v+0.000001)
return np.log(v)
# In[5]:
def viterbi(x, pi, A, B):
"""
x: user input string/sentence: x: "I like playing soccer"
pi: initial probability of tags
A: 给定tag, 每个单词出现的概率
B: tag之间的转移概率
"""
x = [word2id[word] for word in x.split(" ")] # x: [4521, 412, 542 ..]
T = len(x)
dp = np.zeros((T,N)) # dp[i][j]: w1...wi, 假设wi的tag是第j个tag
ptr = np.array([[0 for x in range(N)] for y in range(T)] ) # T*N
# TODO: ptr = np.zeros((T,N), dtype=int)
for j in range(N): # basecase for DP算法
dp[0][j] = log(pi[j]) + log(A[j][x[0]])
for i in range(1,T): # 每个单词
for j in range(N): # 每个词性
# TODO: 以下几行代码可以写成一行(vectorize的操作, 会使得效率变高)
dp[i][j] = -9999999
for k in range(N): # 从每一个k可以到达j
score = dp[i-1][k] + log(B[k][j]) + log(A[j][x[i]])
if score > dp[i][j]:
dp[i][j] = score
ptr[i][j] = k
# decoding: 把最好的tag sequence 打印出来
best_seq = [0]*T # best_seq = [1,5,2,23,4,...]
# step1: 找出对应于最后一个单词的词性
best_seq[T-1] = np.argmax(dp[T-1])
# step2: 通过从后到前的循环来依次求出每个单词的词性
for i in range(T-2, -1, -1): # T-2, T-1,... 1, 0
best_seq[i] = ptr[i+1][best_seq[i+1]]
# 到目前为止, best_seq存放了对应于x的 词性序列
for i in range(len(best_seq)):
print (id2tag[best_seq[i]])
# In[6]:
x = "Social Security number , passport number and details about the services provided for the payment"
viterbi(x, pi, A, B)
词性预测的结果如下:
NNP
NNP
NN
,
NN
NN
CC
NNS
IN
DT
NNS
VBN
IN
DT
NN
Viterbi算法词性预测图解笔记




好博客就要一起分享哦!分享海报
此处可发布评论
评论(0)展开评论
暂无评论,快来写一下吧
展开评论




