<jupyter_start><jupyter_text>1.生成句子实例一：简单语料  1.1 语料1<jupyter_code>simple_grammar = """
sentence => noun_phrase verb_phrase
noun_phrase => Article Adj* noun
Adj* => null | Adj Adj*
verb_phrase => verb noun_phrase
Article =>  一个 | 这个
noun =>   女人 |  篮球 | 桌子 | 小猫
verb => 看着   |  坐在 |  听着 | 看见
Adj =>  蓝色的 | 好看的 | 小小的
"""<jupyter_output><empty_output><jupyter_text>1.2 一些Test<jupyter_code>import random
def adj(): return random.choice('蓝色的 | 好看的 | 小小的'.split('|'))
adj()
print([element.split('=>') for element in [entry for entry in simple_grammar.split('\n')][1:-1]])
print([not element.strip() for element in [entry for entry in simple_grammar.split('\n')]])
print([entry for entry in simple_grammar.split('\n') if entry!=''])<jupyter_output>['sentence => noun_phrase verb_phrase', 'noun_phrase => Article Adj* noun', 'Adj* => null | Adj Adj*', 'verb_phrase => verb noun_phrase', 'Article =>  一个 | 这个', 'noun =>   女人 |  篮球 | 桌子 | 小猫', 'verb => 看着   |  坐在 |  听着 | 看见', 'Adj =>  蓝色的 | 好看的 | 小小的']<jupyter_text>1.3 主体代码<jupyter_code>def grammar(material,com_mark='\n',spec_mark='=>'):
    gram = {}
    for entry in material.split(com_mark):            #按\n划分各行
        if not entry.strip(): continue                      #滤掉非空格或\n
        rule,value = entry.split(spec_mark)
        rule = rule.strip()
        value = value.strip()
        gram[rule] = [v.split() for v in value.split('|')]  #得到语法结构
    return gram
gram_struct = grammar(simple_grammar)
print(gram_struct)
'一个' in gram_struct
def generator(gram = {},target = 'sentence'): 
    result = ''
    if target not in gram:
        #print(target,'not in GRAM.......')
        return target
    #print('Generating',target,'.......')
    #print('Random Choose:',gram[target])
    recv = [generator(gram,t) for t in random.choice(gram[target])]
    result = ''.join([r for r in recv if r!='null'])
    #print('recv:',recv)
    #print('result:',result)
    return result
generator(gram_struct ,target = 'verb_phrase')<jupyter_output><empty_output><jupyter_text>1.4 输出生成的句子<jupyter_code>print(generator(grammar(simple_grammar),'sentence'))<jupyter_output>这个篮球看见这个小小的小小的好看的女人<jupyter_text>2.生成句子实例二：西部世界语料<jupyter_code>#在西部世界里，一个”人类“的语言可以定义为：

human = """
human = 自己 寻找 活动
自己 = 我 | 俺 | 我们 
寻找 = 找找 | 想找点 
活动 = 乐子 | 玩的
"""


#一个“接待员”的语言可以定义为

host = """
host = 寒暄 报数 询问 业务相关 结尾 
报数 = 我是 数字 号 ,
数字 = 单个数字 | 数字 单个数字 
单个数字 = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 
寒暄 = 称谓 打招呼 | 打招呼
称谓 = 人称 ,
人称 = 先生 | 女士 | 小朋友
打招呼 = 你好 | 您好 
询问 = 请问你要 | 您需要
业务相关 = 玩玩 具体业务
玩玩 = null
具体业务 = 喝酒 | 打牌 | 打猎 | 赌博
结尾 = 吗？
"""
host_gram = grammar(host,spec_mark='=')
print(host_gram)
generator(host_gram,target='host')<jupyter_output><empty_output><jupyter_text>2.1 生成host句子:<jupyter_code>for i in range(10):
    print(generator(grammar(host,spec_mark='='),target='host'))<jupyter_output>先生,你好我是8号,请问你要打牌吗？
你好我是7号,您需要赌博吗？
你好我是9号,请问你要打牌吗？
你好我是9号,您需要打猎吗？
您好我是7号,您需要打猎吗？
先生,您好我是42号,请问你要喝酒吗？
小朋友,你好我是59号,您需要打牌吗？
您好我是28号,您需要打猎吗？
你好我是1号,您需要打牌吗？
您好我是71号,请问你要喝酒吗？<jupyter_text>2.2 生成human句子:<jupyter_code>for i in range(10):
    print(generator(grammar(human,spec_mark='='),target='human'))<jupyter_output>我们找找玩的
我们找找玩的
我想找点乐子
我们找找乐子
我想找点乐子
我们找找玩的
俺想找点乐子
俺想找点玩的
我们找找玩的
我找找乐子<jupyter_text>3.基于数据的Language Model  3.1 何为language model?  language model : 计算一句话出现的概率P(String)判断其是否合理，P(String)∈(0,1)，越接近1则越合理，反之越不合理。$$ 数学定义：language\_model(String) = Probability(String) \in (0, 1) $$$$ 理论模型：N-gram: Pr(w_1 w_2 w_3 ... w_n) = Pr(w_1 | w_2 w_3 ... w_ n) * Pr(w2 | w_3 w_4 ... w_n) * ... * Pr(w_(n-1) | w_n) * Pr(w_n)$$$$ 常见模型：2-gram: Pr(w_1 w_2 w_3 ... w_n) \sim Pr(w_1 | w_2 ) * P(w2 | w_3 ) * ... * Pr(w_(n-1) | w_n) * Pr(w_n)$$$$ 常见模型：2-gram: Pr(w_1 w_2 w_3 ... w_n) \sim Pr(w_1) * Pr(w_2 | w_1 ) * P(w3 | w_2 ) * ... * Pr(w_(n-1) | w_n) $$  3.2 训练新闻语料，判断生成句子的合理性  3.2.1 语料切分成小文件<jupyter_code>import os
def split(rawfile,todir,segment):
    if not os.path.exists(todir):                            #目录不存在，新建之
        os.mkdir(todir)          
    else:
        for fname in os.listdir(todir):                      #目录已存在，移除并新建      
            os.remove(os.path.join(todir,fname))
    partnum = 0
    inputfile = open(rawfile,'rb')                            
    chunksize = int(segment*1024*1000)                        #分割文件大小 = segment*1Mb
    while True:
        chunk = inputfile.read(chunksize)                     #读取指定长度
        if not chunk:                                         #切分完否?
            break
        partnum += 1
        filename = os.path.join(todir,(rawfile+'%04d'%partnum))
        fileobj = open(filename,'wb')                          
        fileobj.write(chunk)                                   #写入指定长度
        fileobj.close()
split('article_9k.txt','.\seg',10)
def mergecnt(dict1={},dict2={}):
    if not dict2: return dict1 
    return dict([(k,v+dict1[k]) if k in dict1 else (k,v) for k,v in dict2.items()])<jupyter_output><empty_output><jupyter_text>3.2.2 逐一对小文件进行jieba分词并拼装成Token<jupyter_code>import jieba
def cut(str):
    return jieba.lcut(str)
def getInfo(source_dir):                                       #读取切分的文件，并整合
    token = []
    #word_cnt = {}
    for root, sub_dirs, files in os.walk(source_dir):
        for special_file in files:
            spcial_file_dir = os.path.join(root, special_file)
            with open(spcial_file_dir,'rb') as source_file:
                for line in source_file:
                    token += cut(line)                        #按子文件逐一整合
                    #word_cnt = dict(cnt(token))
                print('>=',special_file,'done')
    print(spcial_file_dir)
    print('token length:',len(token))
    return token
token = getInfo('.\seg')
token[:20]<jupyter_output><empty_output><jupyter_text>3.2.3 统计词频<jupyter_code>from collections import Counter as cnt
cnt(token[:30])
word_cnt = cnt(token)
word_cnt.most_common(50)
word_cnt['你']<jupyter_output><empty_output><jupyter_text>3.2.4 1-gram与2-gram概率计算  单个word出现概率<jupyter_code>def prob1(word=''):
    if word not in word_cnt: 
        #print(word,'is not in Token!')
        return 1/len(token)
    return word_cnt[word]/len(token)  
prob1('此外')
def token_2gram(token = []):
    return [token[i]+token[i+1] for i in range(len(token)-1)]
token_2 = token_2gram(token)
token_2[:20]
token_2gram(cut('今天天气真不错'))
cut('今天天气真不错')
word_2_cnt = cnt(token_2)<jupyter_output><empty_output><jupyter_text>P(Wn|Wn-1) = P(WnWn-1)/P(Wn-1)<jupyter_code>def prob2(word1,word2):     #计算P(W2|W1) = P(W1W2)/P(W1)
    if word1+word2 in token_2:
        return word_2_cnt[word1+word2]/len(token_2)/prob1(word1)
        #return word_2_cnt[word1+word2]/len(token_2)            #此处难道不是计算P(W1W2)?
    else :
        return 1/len(token_2)/prob1(word1)
        #return 1/len(token_2)
prob2('此外','你')<jupyter_output><empty_output><jupyter_text>3.2.5 计算句子的概率(默认2-gram模型)<jupyter_code>def prob_sentence(str,scheme = '2gram'):
    if scheme == '2gram':
        str_token = cut(str)
        #str_token_2 = token_2gram(str_token)
        prob = 1
        for i,word in enumerate(str_token[:-1]):
            #if i < len(str_token)-1:
            #    word_ = str_token[i+1]
            #    prob*=prob2(word,word_)
            #else :
            #    prob*=prob1(word)
            if i == 0 :
                prob*=prob1(word)
            else :
                word_ = str_token[i+1]
                prob*=prob2(word,word_)
        return prob<jupyter_output><empty_output><jupyter_text>3.2.6 一些例子<jupyter_code>prob_sentence('今天的天气真是不错啊')
prob_sentence('小明今天抽奖抽到一台苹果手机')
prob_sentence('小明今天抽奖抽到一架波音747')
prob_sentence('洋葱奶昔来一杯')
prob_sentence('养乐多绿来一杯')
for sen in [generator(gram_struct, target='sentence') for i in range(10)]:
    print('sentence: {} with Prb: {}'.format(sen, prob_sentence(sen)))<jupyter_output>sentence: 一个桌子听着一个好看的女人 with Prb: 7.01023944263084e-18
sentence: 这个篮球听着这个蓝色的篮球 with Prb: 1.184629888933195e-20
sentence: 一个好看的小猫听着一个好看的小猫 with Prb: 6.971265649564411e-23
sentence: 这个好看的篮球看着一个好看的小小的好看的篮球 with Prb: 3.687484316647029e-33
sentence: 一个篮球看见这个小小的桌子 with Prb: 2.30083761608042e-14
sentence: 这个好看的蓝色的小小的小猫看着这个女人 with Prb: 1.1667165302155732e-24
sentence: 这个蓝色的桌子听着这个桌子 with Prb: 1.408020661719889e-19
sentence: 一个篮球听着一个好看的小小的小猫 with Prb: 1.548338520226981e-23
sentence: 一个好看的小小的篮球坐在这个小小的篮球 with Prb: 3.911435400877753e-24
sentence: 这个好看的蓝色的女人看见这个好看的女人 with Prb: 9.131762156458161e-27<jupyter_text>比较生成句子合理性<jupyter_code>need_compared = [
    "今天晚上请你吃大餐，我们一起吃日料 明天晚上请你吃大餐，我们一起吃苹果",
    "真事一只好看的小猫 真是一只好看的小猫",
    "今晚我去吃火锅 今晚火锅去吃我",
    "洋葱奶昔来一杯 养乐多绿来一杯"
]

for s in need_compared:
    s1, s2 = s.split()
    p1, p2 = prob_sentence(s1), prob_sentence(s2)
    
    better = s1 if p1 > p2 else s2
    
    print('{} is more possible'.format(better))
    print('-'*4 + ' {} with probility {}'.format(s1, p1))
    print('-'*4 + ' {} with probility {}'.format(s2, p2))<jupyter_output>今天晚上请你吃大餐，我们一起吃日料 is more possible
---- 今天晚上请你吃大餐，我们一起吃日料 with probility 3.329492941564565e-25
---- 明天晚上请你吃大餐，我们一起吃苹果 with probility 1.9703012027613093e-25
真是一只好看的小猫 is more possible
---- 真事一只好看的小猫 with probility 1.024625101885699e-16
---- 真是一只好看的小猫 with probility 9.645211952811829e-14
今晚我去吃火锅 is more possible
---- 今晚我去吃火锅 with probility 3.1847197581434764e-12
---- 今晚火锅去吃我 with probility 1.0297580191975697e-13
养乐多绿来一杯 is more possible
---- 洋葱奶昔来一杯 with probility 7.704733737087126e-11
---- 养乐多绿来一杯 with probility 5.673005683217094e-08
{'fraction_non_alphanumeric': 0.14680077038305156, 'fraction_numerical': 0.05788572651401669, 'mean_word_length': 3.31333640978311, 'pattern_counts': {'":': 0, '<': 56, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '371899', 'license': 'Apache-2.0', 'n_tokens_mistral': 4756, 'n_tokens_neox': 4742, 'n_words': 693, 'path': 'nlp-backyard/review.ipynb', 'repo_name': 'Enocyl/nlp-backyard', 'size': '9346'}