import random
sentence = """
句子 = 主 謂 賓
主 = 你 | 我 | 他
謂 = 喫 | 喝
賓 = 橘子 | 汽水 | 茶
"""
input: 根據這個語法定語,能夠生成句子
def sentence():
return 主語() + 謂語() + 賓語()
def 主語():
return random.choice('你 | 我 | 他'.split('|'))
def 謂語():
return random.choice('喫 | 喝'.split('|'))
def 賓語():
return random.choice('橘子 | 汽水 | 茶'.split('|'))
for _ in range(10):
print(sentence())
two_number = """
numbers = num numbers | num
num = 0 | 1 | 2 | 3
"""
# def numbers_with_bug():
# return random.choice([num() + numbers_with_bug(), num()])
def num():
return random.choice(' 0 | 1 | 2 | 3'.split('|'))
def numbers():
if random.random() < 0.3:
return num()
else:
return num() + numbers()
numbers()
for _ in range(10):
print(numbers())
怎麼樣在問題場景變化(語法變化)的情況下,你的程序不需要重新寫?
numbers_ops = """
expression => expression op num_op | num_op
num_op => nums op nums
nums => num nums | num
num => 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
op => + | - | * | /
""" # 3 + 4 / 6 * 9
def generate_grammer(grammer_str: str, split='=>'):
grammar = {}
for line in grammer_str.split('\n'):
if not line: continue
expr, formula = line.split(split)
formulas = formula.split('|')
formulas = [f.split() for f in formulas]
grammar[expr.strip()] = formulas
return grammar
def generate_by_grammer(grammar: dict, target=str):
if target not in grammar: return target # 是一個終結符
expr = random.choice(grammar[target])
return ''.join(generate_by_grammer(grammar, t) for t in expr)
generate_by_grammer(grammar, target='expression')
def generate_by_str(grammar_str, target, spliter='=>'):
return generate_by_grammer(grammar=generate_grammer(grammar_str, spliter), target=target)
sentence = """
句子 => 主 謂 賓
主 => 你 | 我 | 他
謂 => 喫 | 喝
賓 => 橘子 | 汽水 | 茶
"""
generate_by_str(numbers_ops, target='expression')
for _ in range(10):
print(generate_by_grammer(generate_grammer(sentence), target='句子'))
#在西部世界裏,一個”人類“的語言可以定義爲:
human = """
human = 自己 尋找 活動
自己 = 我 | 俺 | 我們
尋找 = 找找 | 想找點
活動 = 樂子 | 玩的
"""
假如既然 = """
句子 = if someone state , then do something
if = 既然 | 如果 | 假設
someone = one 和 someone | one
one = 小紅 | 小藍 | 小綠 | 白白
state = 餓了 | 醒了 | 醉了 | 癲狂了
then = 那麼 | 就 | 可以
do = 去
something = 喫飯 | 玩耍 | 去浪 | 睡覺
"""
#一個“接待員”的語言可以定義爲
host = """
host = 寒暄 報數 詢問 業務相關 結尾
報數 = 我是 數字 號 ,
數字 = 單個數字 | 數字 單個數字
單個數字 = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
寒暄 = 稱謂 打招呼 | 打招呼
稱謂 = 人稱 ,
人稱 = 先生 | 女士 | 小朋友
打招呼 = 你好 | 您好
詢問 = 請問你要 | 您需要
業務相關 = 具體業務
具體業務 = 喝酒 | 打牌 | 打獵 | 賭博
結尾 = 嗎?
"""
for _ in range(5):
print(generate_by_str(human, 'human', '='))
for _ in range(5):
print(generate_by_str(假如既然, '句子', '='))
for _ in range(5):
print(generate_by_str(host, 'host', '='))
Data Driven
simpel_programming = '''
programming => assignment logic_programming
assignment => assign change_line assignment | assign change_line
logic_programming => if_stmt | assign | while_loop
while_loop => while { cond } { change_line stmt change_line }
if_stmt => if { cond } { change_line stmt change_line } | if { cond } { change_line stmt change_line } else { change_line stmt change_line }
change_line => /N
cond => var op var
op => | == | < | >= | <= | && | **
stmt => assign | if_stmt
assign => var = var
var => var _ num | words
words => words _ word | word
word => name | info | student | lib | database
nums => nums num | num
num => 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0
'''
generate_by_str(simpel_programming, 'programming', spliter='=>')
def pretty_print(line):
# utility tool function
lines = line.split('/N')
code_lines = []
for i, sen in enumerate(lines):
if i < len(lines) / 2:
#print()
code_lines.append(i * " " + sen)
else:
code_lines.append((len(lines) - i) * " " + sen)
return code_lines
generated_programming = []
for i in range(20):
generated_programming += pretty_print(generate_by_str(simpel_programming, target='programming', spliter='=>'))
generated_programming
計算機如何判斷,那句話說得最對?
10分鐘之後繼續~ 21:42分
形式語言 自然語言
俺想找點玩的
俺想找點玩的
我找找玩的
我們想找點玩的
俺想找點玩的
如果白白和白白醒了,那麼去睡覺
既然小綠醉了,那麼去玩耍
假設白白和白白醒了,可以去睡覺
假設小紅醒了,就去睡覺
如果小紅和白白和白白和白白和小藍和小藍醉了,就去玩耍
你好我是34758626號,請問你要打獵嗎?
女士,您好我是552號,請問你要打牌嗎?
女士,您好我是654號,請問你要打獵嗎?
你好我是638號,您需要打牌嗎?
您好我是22號,您需要打獵嗎?
!ls
ARTILES = open('article_9k.txt').read()
len(ARTILES)
ARTILES[:100]
import jieba
def cut(string): return list(jieba.cut(string))
cut('我是一隻小狗')
ALL_TOKENS = cut(ARTILES)
ALL_TOKENS[:10]
from collections import Counter
word_counts = Counter(ALL_TOKENS)
word_counts.most_common(100)
frequencies = [f for w, f in word_counts.most_common(100)]
x = [i for i in range(100)]
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(x, frequencies)
只要你的數據量足夠大, 那麼,出現次數第N多的單詞,是出現次數最多的單詞的頻率的 1/N
語言模型
1-gram
most_common_500 = [w for w, f in word_counts.most_common(500)]
most_common_to_10000_100500 = [w for w, f in word_counts.most_common(50000)][500:]
''.join(random.sample(most_common_500, k=10))
''.join(random.sample(most_common_500_to_1000, k=10))
1-gram
我衡量一個句子的概率,我就簡單說,這個句子的概率,就等於每個單詞的概率,乘起來!
$ Pr(sententence) = Pr(w_1 w_2… w_n)$
$ Pr(w1 w2 … wn) = Pr(w1 | w_2 w_3 … w_n)Pr(w_2 w_3 … w_n)$
$ Pr(w1 w2 … wn) = Pr(w1 | w_2 w_3 … w_n)Pr(w_2 | w_3 … w_n) Pr( w_3 … w_n)$
$ Pr(w1 w2 … wn) = Pr(w1 | w_2 w_3 … w_n)Pr(w_2 | w_3 … w_n)… Pr( w_{n-1} | w_n)Pr(w_n)$
Pr(AB) = Pr(A|B)Pr(B)
Pr(A|B) = Pr(A) => A 和 B 兩者無關
Pr(你明天上班遲到 | 南非總統今天喝牛奶) != Pr(你明天上班遲到)
Pr(你明天上班遲到 | 南非總統今天喝牛奶) == Pr(你明天上班遲到)
$ Pr(w1 w2 … wn) = Pr(w1 | w_2 w_3 … w_n)Pr(w_2 | w_3 … w_n)… Pr( w_{n-1} | w_n)Pr(w_n)$
$ one-gram = Pr(w1 w2 … wn) = Pr(w1)Pr(w_2)… Pr( w_{n-1})Pr(w_n)$
min_frequences= min([f for w, f in word_counts.most_common()])
def prob_1(word):
# out of vocabulary
if word in word_counts:
return word_counts[word] / len(ALL_TOKENS)
else:
return min_frequences / len(ALL_TOKENS)
prob_1('中國')
prob_1('美國')
from functools import reduce
from operator import mul
reduce(mul, [1, 2, 3, 4, 5, 6, 8])
def _1_gram(sentence):
words = cut(sentence)
return reduce(mul, [prob_1(w) for w in words])
_1_gram('我今天回家')
_1_gram('我今天西瓜')
$ Pr(w1 w2 .. wn) = Pr(w1 | w_2 w_3 .. w_n)Pr(w_2 | w_3 .. w_n).. Pr( w_{n-1} | w_n)Pr(w_n)$
Pr(你 | 今天) = count(你今天) / count(今天)
$ two-gram = Pr(w1*w2 .. wn) = Pr(w1 | w_2)Pr(w_2 | w_3).. Pr( w_{n-1} | w_n)Pr(w_n)$
$ two-gram = Pr(w1*w2 .. wn) = \prod_i^n \frac{count(w_iw_{i+1})}{count(w_{i+1})} Pr(w_n)$
TOKEN_2_GRAM = [''.join(ALL_TOKENS[i:i+2]) for i in range(len(ALL_TOKENS[:-2]))]
len(ALL_TOKENS)
len(TOKEN_2_GRAM)
TOKEN_2_GRAM[10:]
len(TOKEN_2_GRAM)
word_count_2 = Counter(TOKEN_2_GRAM)
$ two-gram = Pr(w1*w2 .. wn) = \prod_i^n \frac{count(w_iw_{i+1})}{count(w_{i+1})} Pr(w_n)$
def prob_2(word1, word2):
combine = word1 + word2
if combine in word_count_2:
return word_count_2[combine] / word_counts[word2]
else: # out of vocabulary
return 1 / len(word_counts)
def _2_gram(sentence):
words = cut(sentence)
prob = 1
for i in range(len(words)-1):
word, next_word = words[i], words[i+1]
prob *= prob_2(word, next_word)
prob *= prob_1(words[-1])
return prob
_2_gram('中國發射了一枚火箭')
_2_gram('中國發射了一枚窗簾')
need_compared = [
('今天晚上請你喫大餐,我們一起喫日料', '今天晚上請你喫大餐,我們一起喫蘋果'),
('真是一隻好看的小貓', '真事一隻好看的小貓'),
('今晚我去喫火鍋', '今晚火鍋去喫我'),
('洋蔥奶昔來一杯', '養樂多綠來一杯')
]
for s1, s2 in need_compared:
print('Pr({}) = {}'.format(s1, _2_gram(s1)))
print('Pr({}) = {}'.format(s2, _2_gram(s2)))