Natural Language Processing Lecture01

Natural Language Processing Lecture01

语法生成树模型

AI 其实就是数据驱动的算法模型。在本例中,通过定义hello_rulessimple_programming 这样的统一格式的语法生成树,来指导生成一个完整的句子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
hello_rules = '''
say_hello = names hello tail
names = name names | name
name = Jhon | Mike | 老梁 | 老刘
hello = 你好 | 您来啦 | 快请进
tail = 呀 | !
'''

simple_programming = '''
if_stmt => if ( cond ) { stmt }
cond => var op var
op => | == | < | >= | <=
stmt => assign | if_stmt
assign => var = var
var => char var | char
char => a | b | c | d | 0 | 1 | 2 | 3
'''

def get_generation_by_gram(grammar_str: str, target, stmt_split='=', or_split='|'):
"""基于 grammar_str 产生句子

grammar_str: 语法生成树
stmt_split: 行内 statement 和 expression 的分隔符
or_split: expression 不同取值的分隔符
"""
rules = dict() # key is the @statement, value is @expression
for line in grammar_str.split('\n'):
if not line: continue # skip the empty line

stmt, expr = line.split(stmt_split)

rules[stmt.strip()] = expr.split(or_split)

# 将语法生成树转换成字典形式
generated = generate(rules, target=target)

return generated

def generate(grammar_rule, target):
"""递归生成字符串拼接句子

grammar_rule: 语法生成树的字典形式
target: 需要查找的 key (statement / expression)
"""
if target in grammar_rule: # 如果是 statement 则取 expression
candidates = grammar_rule[target] # ['name names', 'name']
candidate = random.choice(candidates) #'name names', 'name'
return ''.join(generate(grammar_rule, target=c.strip()) for c in candidate.split())
else:
return target

# 存在的问题:符合生成的 Adj 或 name 会重复,且此时主语宾语与现实世界表述有差异
senc = get_generation_by_gram(hello_rules, target='say_hello', stmt_split='=')

print(senc)

N-gram 算法模型

模型介绍

N-gram 是一种基于统计语言模型的算法。该模型基于这样一种假设,第 N 个词的出现只与前面 N-1个词相关,而与其它任何词都不相关,整句的概率就是各个词出现概率的乘积。

N-gram 语义切分的主要思想就是将文本数据从第一个字符开始, 在给定的长序列中, 从左向右以 n 个字符的大小来进行滑动, 产生长度为n的部分重叠且连续短子序列作为一个 N-gram 语义切分之后的短序列片段 (gram) 。

常用的是二元的 Bi-Gram 和三元的 Tri-Gram。

公式方法

当 n = 1 时,一个一元模型(unigram model)即为:

\[P(w_1,w_2,\dots,w_m) = \prod P(w_i)\]

\[P(w_i)=\frac{C(w_i)}{\sum_{\forall k}C(w_k)}=\frac{C(w_i)}{N}\] 当 n = 2 时,一个二元模型(bigram model)即为:

\[ P(w_1,w_2,\cdots,w_n) = \prod P(w_i|w_{i-1}) \]

\[P(w_{i+1}|w_i)=\frac{P(w_{i+1},w_i)}{P(w_i)}= \frac{C(w_i, w_{i+1})}{\sum_{\forall k}C(w_i,w_k)}=\frac{C(w_i,w_{i+1})}{C(w_i)}\]

当 n = 3 时,一个三元模型(bigram model)即为:

\[ P(w_1,w_2,\cdots,w_n) = \prod P(w_i|w_{i-1}w_{i-2}) \]

\[P(w_i|w_{i-2}w_{i-1})=\frac{C(w_{i-2},w_{i-1},w_i)}{C(w_{i-2}w_{i-1})}\]

对于 n-gram model 而言:

\[P(w_i|w_{i-n-1},\dots,w_{i-1})=\frac{C(w_{i-n-1},\dots,w_i)}{C(w_{i-n-1},\dots,w_{i-1})}\]

样题举例

数据库来源:https://github.com/ezioyuan/NLP-Assignment/tree/master/lesson1/datasets/article_9k.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import jieba  # 中文语料库,用 jieba 分词进行划分

corpus = '.../article_9k.txt'
FILE = open(corpus).read()

max_length = 1000000

sub_file = FILE[:max_length] # 语料库过大,所以我们只取部分进行测试

def cut(string):
return list(jieba.cut(string)) # 返回对语料库分词后的列表,按出现顺序

TOKENS = cut(sub_file) # 分词列表
words_count = Counter(TOKENS) # Counter 对列表转化,统计每个词频数

_2_gram_words = [ # 二元词组列表
TOKENS[i] + TOKENS[i+1] for i in range(len(TOKENS)-1)
]
_2_gram_word_counts = Counter(_2_gram_words) # 统计词频

def get_gram_count(word, wc): # 返回 word 在语料库的频数
if word in wc: return wc[word]
else:
return wc.most_common()[-1][-1] # 返回语料库中最小的频数

def two_gram_model(sentence):
# 2-gram langauge model
tokens = cut(sentence)

probability = 1

for i in range(len(tokens)-1):
# 按公式计算
word = tokens[i]
next_word = tokens[i+1]

_two_gram_c = get_gram_count(word+next_word, _2_gram_word_counts)
_one_gram_c = get_gram_count(next_word, words_count)
pro = _two_gram_c / _one_gram_c

probability *= pro

return probability

two_gram_model('此外自本周6月12日起除小米手机6等15款机型')
# 3.0550026391456175e-26
# NLP

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×