lesson-01-course-code

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

語言模型

languagemodel=Pr(sentence)language-model = Pr(sentence)

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)))

1. 數據思維 Data Driven

2. 數學模型 -> 編程實現

More Data, Better Result

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章