• 自然语言处理


    自然语言处理

    1. NLTK python的NLP工具包

    2. WordNet 英文的语义网络

    3. BabelNet 多语言版的语义网络, 全部数据有29GB, 需要以科研的身份申请, 否则只能在线上用每天限量1k的接口. 等有空试验下接口.

    4. 决策树分类器

    5. 朴素贝叶斯分类器

    6. 最大熵分类器 -- 需要补习概率论知识了

    Update 2018-06-15: 浙大概率论第四版, 看了两章, 看懂贝叶斯公式了. 但是没看到有关最大熵的章节, 继续看NLTK, 百度了一些最大熵的说明, 这次大概看懂了, 但是后面的词性标注, 句法标注还是看得很懵, 貌似还是需要很多语言相关的先验知识. 下载了deep learning book 中文版, 打算直接看深度学习吧

    基础知识

    词向量和语言模型 http://licstar.net/archives/328

    分词参考汇总

    SNS文本数据挖掘 http://www.matrix67.com/blog/archives/5044

    1. 基于AC自动机的分词

    https://spaces.ac.cn/archives/3908

    这个是基于词库(用AC自动机载入)的分词,用动态规划得到概率最大的分词结果

    import ahocorasick
    import math
    
    
    def load_dic(dicfile):
        dic = ahocorasick.Automaton()
        total = 0.0
        with open(dicfile, 'r', encoding='utf-8') as dicfile:
            words = []
            for line in dicfile:
                line = line.split(' ')
                count = int(line[1])
                if count <= 0:
                    count = 1
                words.append((line[0], count))
                total += int(line[1])
        for word,occurs in words:
            dic.add_word(word, (word, math.log(occurs/total))) #这里使用了对数概率,防止溢出
        dic.make_automaton()
        return dic
    
    def print_all_cut(sentence):
        words = []
        for i,j in dic.iter(sentence):
            print(i, j)
    
    
    dic = load_dic('dict.txt')
    # 可以看到, 序号就是词在句中的位置
    print_all_cut('最大匹配法是指从左到右逐渐匹配词库中的词语')
    
    '''
    使用动态规划, 
    每次用start处的概率加上本词的概率, 如果end处未赋值或者end处的值比这个小, 就用这个值代替
    如果start处还没有值, 就取start之前的最大的值造一个
    '''
    def max_proba_cut(sentence):
        paths = {0:([], 0)}
        end = 0
        for i,j in dic.iter(sentence):
            start,end = 1+i-len(j[0]), i+1
            if start not in paths:
                last = max([i for i in paths if i < start])
                paths[start] = (paths[last][0]+[sentence[last:start]], paths[last][1]-10)
            proba = paths[start][1]+j[1]
            if end not in paths or proba > paths[end][1]:
                paths[end] = (paths[start][0]+[j[0]], proba)
        if end < len(sentence):
            return paths[end][0] + [sentence[end:]]
        else:
            return paths[end][0]
    
    path = max_proba_cut('最大匹配法是指从左到右逐渐匹配词库中的词语')
    print(path)
    

    2A. 基于信息熵的新词发现 

    https://spaces.ac.cn/archives/3491

    这是无词库的分词方式,对语料预处理,去掉中英文标点仅保留中英文数字并拆分为句子,对所有内容进行1~N元划分,分别计算支持度和熵

    import numpy as np
    import pandas as pd
    import re
    from numpy import log, min
    
    f = open('d:/WorkPython/tmp/TianLongBaBu.txt', 'r', encoding='utf-8')  # 读取文章
    s = f.read()  # 读取为一个字符串
    
    # 定义要去掉的标点字
    drop_dict = [u',', u'
    ', u'。', u'、', u':', u'(', u')', u'[', u']', u'.', u',', u' ', u'u3000', u'”', u'“', u'?', u'?',
                 u'!', u'‘', u'’', u'…']
    for i in drop_dict:  # 去掉标点字
        s = s.replace(i, '')
    
    # 为了方便调用,自定义了一个正则表达式的词典
    myre = {2: '(..)', 3: '(...)', 4: '(....)', 5: '(.....)', 6: '(......)', 7: '(.......)'}
    
    min_count = 10  # 录取词语最小出现次数
    min_support = 30  # 录取词语最低支持度,1代表着随机组合
    min_s = 3  # 录取词语最低信息熵,越大说明越有可能独立成词
    max_sep = 4  # 候选词语的最大字数
    t = []  # 保存结果用。
    
    l = list(s) # 将字符串拆成字符列表
    serial = pd.Series(l) # 给每个字符加上编号, 从0开始
    t.append(serial.value_counts())  # 对每个字符计算字频, 会产生一个按字频倒序的列表, 作为t[0]
    tsum = t[0].sum()  # 统计总字数, .sum()函数是pandas.Series的一个函数
    rt = []  # 保存结果用
    
    for m in range(2, max_sep + 1):
        print(u'正在生成%s字词...' % m)
        t.append([])
        for i in range(m):  # 生成所有可能的m字词, 放到t[m-1]
            t[m - 1] = t[m - 1] + re.findall(myre[m], s[i:])
    
        t[m - 1] = pd.Series(t[m - 1]).value_counts()  #  对每个词计算词频, 产生按字频倒序的列表, 作为t[m-1]
        t[m - 1] = t[m - 1][t[m - 1] > min_count]  # 去掉词频小于min_count的词
        tt = t[m - 1][:] # 复制刚才产生的列表
        '''
        用map的方式,将刚才产生的列表的每个元素,一一用lambda里的方法去计算, 这里
        ms in tt.index ms是这个元素的值, 例如'段誉' 
        aa = ms[:m-1] 前一部分, 例如'段'  
        bb = tmp[m-1:] 后一部分, 例如'誉'
        cc = t[m - 1][tmp] 这个元素的词频
        dd = t[m - 2][tmp[:m - 1]] 前一部分对应元素的词频
        ee = t[0][tmp[m - 1:]] 后一部分对应元素的词频
        '''
        ld = lambda ms: tsum * t[m - 1][ms] / t[m - 2 - k][ms[:m - 1 - k]] / t[k][ms[m - 1 - k:]]
        for k in range(m - 1):
            qq = np.array(list(map(ld, tt.index))) > min_support  # 最小支持度筛选。
            tt = tt[qq] # pandas.Series可以通过[True, False, ...]这样的序列提取子集合, 不断滤掉未达到最小支持度的词
        rt.append(tt.index)
    
    
    def cal_S(sl):  # 信息熵计算函数
        return -((sl / sl.sum()).apply(log) * sl / sl.sum()).sum()
    
    
    for i in range(2, max_sep + 1):
        print(u'正在进行%s字词的最大熵筛选(%s)...' % (i, len(rt[i - 2])))
        pp = []  # 保存所有的左右邻结果
        for j in range(i + 2):
            pp = pp + re.findall('(.)%s(.)' % myre[i], s[j:])
        pp = pd.DataFrame(pp).set_index(1).sort_index()  # 先排序,这个很重要,可以加快检索速度
        index = np.sort(np.intersect1d(rt[i - 2], pp.index))  # 作交集
        # 下面两句分别是左邻和右邻信息熵筛选
        index = index[np.array(list(map(lambda s: cal_S(pd.Series(pp[0][s]).value_counts()), index))) > min_s]
        rt[i - 2] = index[np.array(list(map(lambda s: cal_S(pd.Series(pp[2][s]).value_counts()), index))) > min_s]
    
    # 下面都是输出前处理
    for i in range(len(rt)):
        t[i + 1] = t[i + 1][rt[i]]
        t[i + 1].sort_values(ascending=False)
    
    # 保存结果并输出
    pd.DataFrame(pd.concat(t[1:])).to_csv('result.txt', header=False)
    

    2B. 基于切分的新词发现 

    https://spaces.ac.cn/archives/3913

    简单地通过计算相邻两字出现的概率,断开概率低于阈值的字而达到分词的效果

    import re
    import json
    
    from collections import defaultdict #defaultdict是经过封装的dict,它能够让我们设定默认值
    from tqdm import tqdm #tqdm是一个非常易用的用来显示进度的库
    from math import log
    
    def load_texts(text_file):
        with open(text_file, 'r', encoding='utf-8') as articles:
            for article in articles:
                json_obj = json.loads(article)
                if 'content' in json_obj:
                    yield json_obj['content']
    
    
    class Find_Words:
        def __init__(self, min_count=10, min_pmi=0):
            self.min_count = min_count
            self.min_pmi = min_pmi
            self.chars, self.pairs = defaultdict(int), defaultdict(int)
            #如果键不存在,那么就用int函数初始化一个值,int()的默认结果为0
            self.total = 0.
    
        # 预切断句子,以免得到太多无意义(不是中文、英文、数字)的字符串
        def text_filter(self, texts):
            for a in tqdm(texts):
                for t in re.split(u'[^u4e00-u9fa50-9a-zA-Z]+', a):
                    #这个正则表达式匹配的是任意非中文、非英文、非数字,因此它的意思就是用任意非中文、非英文、非数字的字符断开句子
                    if t:
                        yield t
    
        # 计数函数,计算单字出现频数、相邻两字出现的频数
        def count(self, texts):
            for text in self.text_filter(texts):
                self.chars[text[0]] += 1
                for i in range(len(text)-1):
                    self.chars[text[i+1]] += 1
                    self.pairs[text[i:i+2]] += 1
                    self.total += 1
            self.chars = {i:j for i,j in self.chars.items() if j >= self.min_count} #最少频数过滤
            self.pairs = {i:j for i,j in self.pairs.items() if j >= self.min_count} #最少频数过滤
            self.strong_segments = set()
            for i,j in self.pairs.items(): #根据互信息找出比较“密切”的邻字
                _ = log(self.total*j/(self.chars[i[0]]*self.chars[i[1]]))
                if _ >= self.min_pmi:
                    self.strong_segments.add(i)
    
        # 根据前述结果来找词语
        def find_words(self, texts):
            self.words = defaultdict(int)
            for text in self.text_filter(texts):
                s = text[0]
                for i in range(len(text)-1):
                    if text[i:i+2] in self.strong_segments: #如果比较“密切”则不断开
                        s += text[i+1]
                    else:
                        self.words[s] += 1 #否则断开,前述片段作为一个词来统计
                        s = text[i+1]
            self.words = {i:j for i,j in self.words.items() if j >= self.min_count} #最后再次根据频数过滤
    
    
    fw = Find_Words(16, 1)
    fw.count(load_texts('D:/WorkPython/tmp/articles.json'))
    fw.find_words(load_texts('D:/WorkPython/tmp/articles.json'))
    
    import pandas as pd
    words = pd.Series(fw.words).sort_values(ascending=False)
    words.to_csv('output.csv')
    

    3. 字标注法与HMM模型 

    https://spaces.ac.cn/archives/3922

    4. 基于双向LSTM的seq2seq字标注 

    https://spaces.ac.cn/archives/3924

    5. 基于语言模型的无监督分词 

    https://spaces.ac.cn/archives/3956

    使用KenLM作为训练工具,使用预先分好词的语料进行训练,生成klm格式的语言模型后,在python中载入处理分词。

    6. 基于全卷积网络的中文分词 https://spaces.ac.cn/archives/4195

    7. 用词典完成深度学习分词 https://spaces.ac.cn/archives/4245

    8. 改进新词发现算法 https://spaces.ac.cn/archives/6920

    专业词汇的无监督挖掘 https://spaces.ac.cn/archives/6540

    Keras seq2seq自动生成标题 https://kexue.fm/archives/5861

  • 相关阅读:
    springboot~使用docker构建gradle项目
    CH BR8(小学生在上课-逆元和互质数一一对应关系)
    UNIX环境高级编程第二版代码笔记
    【Linux学习笔记】用nc实现两台主机间的文件传输(不需要输密码)
    hdu 1159
    轻量级的原型设计工具-Axure RP
    在Ubuntu 12.10 上安装部署Openstack
    [Android 中级]Voip之CSipSimple类库的编绎
    OpenStack云计算快速入门之一:OpenStack及其构成简介
    OpenStack云计算快速入门之二:OpenStack安装与配置
  • 原文地址:https://www.cnblogs.com/milton/p/9172492.html
Copyright © 2020-2023  润新知