隐马尔可夫模型理论知识:
角色:收拾烂摊子的角色
1) 生成方式
2) 路径选择(viterbi算法)——>动态规划
上篇文章讲到语言模型(1,2,3)
二元语言模型 == 一阶马尔科夫模型
马尔科夫模型有3类重要参数:
1、状态
2、初始概率
初始概率计算方法举例:
假设有100篇文章,
时光荏苒 30篇 -> 30 / 100
今天 10篇
开心 5篇
加班 1篇
3.转移概率计算方法举例:
x x x x x x x x x x x x x x A B x x x x x A B x x x x A C x x x x
P(B|A) = 2/3
P(C|A) = 1/3
计算的前提条件:大量的文章
因为马尔科夫模型是针对一个序列建模的,现实中会有多个序列(比如语音识别),因此而产生隐马尔可夫模型
双序列举例:
词性标注
隐马尔科夫模型中有5类重要参数:
1、状态,M个 = 4(位置信息)*20(词性信息) = 80(大概有80个状态)
2、初始概率:M个
3、转移概率:M*M(一个状态到另外一个状态的概率)
4、发射概率:M*N
5、观察,N个 = 2000(有多少个汉字,就有多少个观察)
BMES状态:举例:
初始概率:
获取方法:统计
假设有100篇文章,
时光荏苒 30篇 那么初始概率为-> 30 / 100
转移概率:
状态概率:每一个状态到一个汉字的概率
P(S1,S2,S3,O1,O2,O3) 联合概率
= P(S1) * P(O1|S1) * P(S2|S1) *** **
viterbi动态规划最优路径算法
目的:将零散的词汇粘在一起
实践:倒排索引
1.原始数据:
思路:
1.map做分词:name->token,token,token
2.reduce(聚合)
token1 -> name name name
代码:
map.py:
#!/usr/bin/python
import os
import sys
os.system('tar xvzf jieba.tar.gz > /dev/null')
reload(sys)
sys.setdefaultencoding('utf-8')
sys.path.append("./")
import jieba
import jieba.posseg
import jieba.analyse
def mapper_func():
for line in sys.stdin:
ss = line.strip().split('\t')
if len(ss) != 2:
continue
music_id = ss[0].strip()
music_name = ss[1].strip()
tmp_list = []
for x, w in jieba.analyse.extract_tags(music_name, withWeight=True):
tmp_list.append((x, float(w)))
final_token_score_list = sorted(tmp_list, key=lambda x: x[1], reverse=True)
print '\t'.join([music_id, music_name, ''.join([''.join([t_w[0], str(t_w[1])]) for t_w in final_token_score_list])])
if __name__ == "__main__":
module = sys.modules[__name__]
func = getattr(module, sys.argv[1])
args = None
if len(sys.argv) > 1:
args = sys.argv[2:]
func(*args)
倒排map_inverted.py:
#!/usr/bin/python
import os
import sys
def mapper_func():
for line in sys.stdin:
ss = line.strip().split('\t')
if len(ss) != 3:
continue
music_id = ss[0].strip()
music_name = ss[1].strip()
music_fealist = ss[2].strip()
for fea in music_fealist.split(''):
token, weight = fea.strip().split('')
print '\t'.join([token, music_name, weight])
if __name__ == "__main__":
module = sys.modules[__name__]
func = getattr(module, sys.argv[1])
args = None
if len(sys.argv) > 1:
args = sys.argv[2:]
func(*args)
red_inverted.py:
#!/usr/bin/python
import os
import sys
def reducer_func():
cur_token = None
m_list = []
for line in sys.stdin:
ss = line.strip().split('\t')
if len(ss) != 3:
continue
token = ss[0].strip()
name = ss[1].strip()
weight = float(ss[2].strip())
if cur_token == None:
cur_token = token
if cur_token != token:
final_list = sorted(m_list, key=lambda x: x[1], reverse=True)
print '\t'.join([cur_token, ''.join([''.join([name_weight[0], str(name_weight[1])]) for name_weight in final_list])])
cur_token = token
m_list = []
m_list.append((name, weight))
final_list = sorted(m_list, key=lambda x: x[1], reverse=True)
print '\t'.join([cur_token, ''.join([''.join([name_weight[0], str(name_weight[1])]) for name_weight in final_list])])
if __name__ == "__main__":
module = sys.modules[__name__]
func = getattr(module, sys.argv[1])
args = None
if len(sys.argv) > 1:
args = sys.argv[2:]
func(*args)
脚本run.sh:
HADOOP_CMD="/usr/local/src/hadoop-2.6.5/bin/hadoop"
STREAM_JAR_PATH="/usr/local/src/hadoop-2.6.5/share/hadoop/tools/lib/hadoop-streaming-2.6.5.jar
"
INPUT_FILE_PATH_1="/music_meta.txt.small"
OUTPUT_Z_PATH="/output_z_fenci"
OUTPUT_D_PATH="/output_d_fenci"
$HADOOP_CMD fs -rmr $OUTPUT_Z_PATH
$HADOOP_CMD fs -rmr $OUTPUT_D_PATH
# Step 1.
$HADOOP_CMD jar $STREAM_JAR_PATH \
-input $INPUT_FILE_PATH_1 \
-output $OUTPUT_Z_PATH \
-mapper "python map.py mapper_func" \
-jobconf "mapred.reduce.tasks=0" \
-jobconf "mapreduce.map.memory.mb=4096" \
-jobconf "mapred.job.name=jieba_fenci_demo" \
-file "./jieba.tar.gz" \
-file "./map.py"
# Step 2.
$HADOOP_CMD jar $STREAM_JAR_PATH \
-input $OUTPUT_Z_PATH \
-output $OUTPUT_D_PATH \
-mapper "python map_inverted.py mapper_func" \
-reducer "python red_inverted.py reducer_func" \
-jobconf "mapred.reduce.tasks=2" \
-jobconf "mapreduce.map.memory.mb=4096" \
-jobconf "mapred.job.name=jieba_fenci" \
-file "./map_inverted.py" \
-file "./red_inverted.py"
第一阶段中间结果:
最后结果:
这就是召回:token检索item