自然语言处理(nlp) 学习--分词

## day1自然语言处理基础梳理


前言

NLP(Natural Language Processing,自然语言处理)是计算机科学领域以及人工智能领域的一个重要的研究方向,它研究用计算机来处理、理解以及运用人类语言(如中文、英文等),达到人与计算机之间进行有效通讯。
自然语言处理NLP的应用:语音识别系统;问答系统;机器翻译;文本摘要; 情感分析;基于模板的聊天机器人;文本分类;主题分割等。
NLP基本可以分为两个部分:自然语言处理以及自然语言生成,本章先对自然语言处理进行简单概述。


一、nlp基本处理流程

①理解问题陈述②收集数据库/语料③数据集/语料分析④数据集预处理⑤特征工程⑥决定所使用的计算技术,如机器学习、基于规则的方法等⑦应用计算技术⑧测评和评估系统结果⑨参数调优⑩满意的结果

二、数据库/语料库&数据集/语料分析

1.数据库/语料库:

①单语语料库②双语语料库③多语言语料库

cmd安装 nltk

pip install nltk;

nltk包含了以下四种语料库:
①孤立语料库;②分类语料库;③重叠语料库;④时序语料库

2.数据集/语料分析

①挑选数据
你可以使用下面的链接下载免费数据集:https://github.com/caesar0301/awesome-public-datasets
https://www.kaggle.com/datasets
https://www.reddit.com/r/datasets
或者爬虫(webscrapy)

②预处理数据
1.格式化;2.清洗;3.采样;4.转换数据(文本数据转化成数值数据)

③转换数据
基于规则的自然语言处理只适合用在相对简单的场景,其优势在于可以快速实现一个简单可用的语义理解模块。

三、基于规则的方法和基于统计的方法

1.方法概述

①基于规则的方法
人工定义很多语法规则,然后自然语言理解根据这些规则解析输入该模块的文本。
优点:灵活,自行定义规则不依赖训练数据;缺点:大量的规则,人工维护的难度增加。

②基于统计的方法
通常使用大量的数据训练模型,并使用模型执行各种上层语义任务。输入是句子的文本特征,输出是句子文本特征所属的意图分类。(HMM/CRF)
优点:数据驱动且健壮性较好;缺点:训练数据难以获得且模型难以解释和调参。

基于规则的自然语言处理只适合用在相对简单的场景,其优势在于可以快速实现一个简单可用的语义理解模块。

2.词法分析(分词+词性标注)

分词:通过计算机自动识别出句子的词,在词间加入边界标记符,将输入的字串切分为单独的词语。

基于规则的方法:正向最大匹配法、逆向最大匹配法、双向扫描法、逐词遍历法。工具:IKAnalyzer、庖丁解牛
正向最大匹配法(Maximum Match Method,MM法):
正向最大匹配的算法描述如下:
①从左向右取待切分汉语句的m个字符作匹配字段,m为机器词典中最长词条的字符数。
②查找机器词典并进行匹配。若匹配成功,则将这个匹配字段作为一个词切分出来。若匹配不成功,则将这个匹配字段的最后一个字去掉,剩下的字符串作为新的匹配字段,进行再次匹配,重复以上过程,直到切分出所有词为止。
下面展示 正向最大匹配法

#正向最大匹配
class MM(object):
    def __init__(self, dic_path): 
        self.dictionary = set()
        self.maximum = 0
        #读取机器词典最长词条的字符数
        with open(dic_path, 'r', encoding='utf8') as f:
            for line in f:
                line = line.strip()
                if not line:
                    continue
                self.dictionary.add(line)
                self.maximum = len(line)
    def cut(self, text):
       result = []
        index = 0
        text_length = len(text)
        while text_length > index:
            for size in range(self.maximum + index, index, -1):
                piece = text[index:size]
                if piece in self.dictionary:
                    index = size - 1
                    break
            index = index + 1
            result.append(piece + '----')
        print(result)
        
def main():
    text = "南京市长江大桥"

    tokenizer = MM('./data/imm_dic.utf8')//词典位置
    print(tokenizer.cut(text))

逆向最大匹配法(Reverse Maximum Match Method,RMM法)
将文档进行倒排处理,生成逆序文档。然后,根据逆序词典,对逆序文档用MM法处理即可。
由于汉语中偏正结构较多,逆向最大匹配法比正向最大匹配法的误差要小。
下面展示逆向最大匹配法

#逆向最大匹配
class IMM(object):
    def __init__(self, dic_path): 
        self.dictionary = set()
        self.maximum = 0
        #读取机器词典最长词条的字符数
        with open(dic_path, 'r', encoding='utf8') as f:
            for line in f:
                line = line.strip()
                if not line:
                    continue
                self.dictionary.add(line)
                self.maximum = len(line)
    def cut(self, text):
        result = []
        index = len(text)
        while index > 0:
            word = None
            for size in range(self.maximum, 0, -1)://逆序遍历
                if index - size < 0:
                    continue
                piece = text[(index - size):index]
                if piece in self.dictionary:
                    word = piece
                    result.append(word)
                    index -= size
                    break
            if word is None:
                index -= 1
        return result[::-1]

def main():
    text = "南京市长江大桥"

    tokenizer = IMM('./data/imm_dic.utf8')//词典位置
    print(tokenizer.cut(text))

双向最大匹配法(Bi-directction Matching method)
是将正向最大匹配法得到的分词结果和逆向最大匹配法得到的结果进行比较,然后按照最大匹配原则,选取词数切分最少的作为结果。

基于统计的方法:主要思想是相连的字在不同的文本中出现的次数越多,就证明这相连的字很可能就是一个词。
①建立统计语言模型。
②对句子进行单词划分,然后对划分结果进行概率计算,获得概率最大的分词方式。这里就用到了统计学习算法,如隐含马尔可夫(HMM)、条件随机场(CRF)、支持向量机(SVM)及深度学习等。
隐含马尔可夫(HMM)
隐含马尔可夫(HMM)是将分词作为字在字串中的序列标注任务来实现的。其基本思路是:每个字在构造一个特定的词语时都占据着一个特定的构词位置,现规定每个字最多只有四个构词位置:即B(词首)、M(词中)、E(词尾)和 S(单独成词),那么下面句子1)的分词结果可以表示成2)所示的逐字标注形式:

1)中文/分词/是/文本处理/不可或缺/的/一步!

2)中/B 文/E 分/B 词/E 是/S 文/B 本/M 处/M 理/M 不/B 可/M 或/M 缺/E 的/S 一/B 步/E !/S

下面展示 隐含马尔可夫

class HMM(object):
    def __init__(self):
        self.model_file = './data/hmm_model.pkl'
        self.state_list = ['B', 'M', 'E', 'S']
        self.load_para = False

    def try_load_model(self, trained):
        if trained:
            import pickle //pickle提供了一个简单的持久化功能。可以将对象以文件的形式存放在磁盘上
            with open(self.model_file, 'rb') as f:
                self.A_dic = pickle.load(f) //反序列化对象。将文件中的数据解析为一个Python对象
                self.B_dic = pickle.load(f)
                self.Pi_dic = pickle.load(f)
                self.load_para = True
        else:
            self.A_dic = {}
            self.B_dic = {}
            self.Pi_dic = {}
            self.load_para = False

    def train(self, path):
        self.try_load_model(False)
        Count_dic = {}

        def init_parameters():
            for state in self.state_list:
                self.A_dic[state] = {s: 0.0 for s in self.state_list}
                self.Pi_dic[state] = 0.0
                self.B_dic[state] = {}
                Count_dic[state] = 0

        def makeLabel(text):
            out_text = []
            if len(text) == 1:
                out_text.append('S')
            else:
                out_text += ['B'] + ['M'] * (len(text) - 2) + ['E']
            return out_text

        init_parameters()
        line_num = -1
        words = set()
        with io.open(path, encoding='utf8') as f:
            for line in f:
                line_num += 1
                line = line.strip()
                if not line:
                    continue
                word_list = [i for i in line if i != ' ']
                words |= set(word_list)

                linelist = line.split()

                line_state = []
                for w in linelist:
                    line_state.extend(makeLabel(w))

                assert(len(word_list) == len(line_state))
                //用于判断一个表达式,在表达式条件为 false 的时候触发异常

                for k, v in enumerate(line_state):
                    Count_dic[v] += 1
                    if k == 0:
                        self.Pi_dic[v] += 1
                    else:
                        self.A_dic[line_state[k-1]][v] += 1
                        self.B_dic[line_state[k]][word_list[k]] = \
                            self.B_dic[line_state[k]].get(word_list[k], 0) + 1.0
        self.Pi_dic = {k: v * 1.0 / line_num for k, v in self.Pi_dic.items()}
        self.A_dic = {k: {k1: v1 / Count_dic[k] for k1, v1 in v.items()}
                      for k, v in self.A_dic.items()}
        self.B_dic = {k: {k1: (v1 + 1) / Count_dic[k] for k1, v1 in v.items()}
                      for k, v in self.B_dic.items()}

        import pickle
        with open(self.model_file, 'wb') as f:
            pickle.dump(self.A_dic, f)
            pickle.dump(self.B_dic, f)
            pickle.dump(self.Pi_dic, f)
//序列化对象,并将结果数据流写入到文件对象中。
        return self


    def viterbi(self, text, states, start_p, trans_p, emit_p):
        V = [{}]
        path = {}
        for y in states:
            V[0][y] = start_p[y] * emit_p[y].get(text[0], 0)
            path[y] = [y]
        print(V)
        print(path)
        for t in range(1, len(text)):
            V.append({})
            newpath = {}

            neverSeen = text[t] not in emit_p['S'].keys() and \
                text[t] not in emit_p['M'].keys() and \
                text[t] not in emit_p['E'].keys() and \
                text[t] not in emit_p['B'].keys()
            for y in states:
                emitP = emit_p[y].get(text[t], 0) if not neverSeen else 1.0
                (prob, state) = max(
                    [(V[t-1][y0] * trans_p[y0].get(y, 0) * emitP, y0) for y0 in states if V[t-1][y0] > 0]
                )
                V[t][y] = prob
                newpath[y] = path[state] + [y]
            path = newpath
        if emit_p['M'].get(text[-1], 0) > emit_p['S'].get(text[-1], 0):
            (prob, state) = max([(V[len(text) - 1][y], y) for y in ('E', 'M')])
        else:
            (prob, state) = max([(V[len(text) - 1][y], y) for y in states])
        return (prob, path[state])

    def cut(self, text):
        import os
        if not self.load_para:
            self.try_load_model(os.path.exists(self.model_file))
        prob, pos_list = self.viterbi(text, self.state_list, self.Pi_dic, self.A_dic, self.B_dic)
        begin, next = 0, 0
        for i, char in enumerate(text):
            pos = pos_list[i]
            if pos == 'B':
                begin = i
            elif pos == 'E':
                yield text[begin: i+1]
                next = i + 1
            elif pos == 'S':
                yield char
                next = i + 1
        if next < len(text):
            yield text[next:]


if __name__ == '__main__':
    hmm = HMM()
    # hmm.train('./data/trainCorpus.txt_utf8')
    text = '这是一个非常棒的方案'
    res = hmm.cut(text)
    print(list(res));
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 自然语言处理(Natural Language Processing,简称NLP)是计算机科学与人工智能领域的一个重要研究方向,目的是让计算机能够理解、处理和生成人类的自然语言。NLP-100例是一份经典的NLP问题集合,包含了各种与自然语言处理相关的问题和挑战。 这份NLP-100例涵盖了从基础的文本处理到更高级的自然语言理解和生成的问题。例如,其中包括了文本预处理、词频统计、语法分析、词性标注、实体识别、情感分析、机器翻译等任务。 NLP-100例的目的是帮助研究者和开发者更好地理解NLP领域的核心问题和技术,同时提供一些典型的案例和数据集供实践和研究使用。通过完成这些例题,可以锻炼自己在NLP领域的能力和技术,提高对自然语言的处理和理解能力。 此外,NLP-100例也为研究者提供了一个可以与其他人交流和探讨的平台。研究者可以使用相同的数据集和问题进行实验和评估,从而更好地了解NLP技术的优劣和进展。 总之,NLP-100例是一个对NLP进行实践和研究的重要资源。通过解决这些例题,可以深入理解自然语言处理的基础和技术,掌握各种NLP任务的方法和技巧。同时,它也是一个促进交流和合作的平台,为NLP研究者提供了一个共同的基础和语言。 ### 回答2: 自然语言处理(Natural Language Processing,简称NLP)是研究计算机与人类自然语言之间的交互的一门学科。NLP-100例指的是日本的一个NLP入门教程,包含了100个常见的NLP问题和对应的解答。 NLP-100例涵盖了从文本处理到语义理解等多个方面的问题。其中,一些例子包括:文本的分词、词性标注、句法分析、语义角色标注和文本分类等。 以分词为例,分词是将一段连续的文本分割成词语的过程。在NLP-100例中,可以通过使用Python中的分词工具NLTK(Natural Language Toolkit)来实现分词功能。 另外,对于文本的词性标注,NLP-100例提供了使用POS(Part-Of-Speech)标记对文本中的每个词进行词性标注的方法。可以使用NLTK提供的POS标注工具来实现。 此外,NLP-100例还包括了语义角色标注的问题,语义角色标注是为了确定句子中的谓语动词所承担的语义角色,如施事者、受事者、时间等。可以使用Stanford CoreNLP工具包来实现语义角色标注。 最后,NLP-100例还介绍了文本分类的问题,文本分类是将文本划分到预定义的类别中。可以使用机器学习算法,如朴素贝叶斯或支持向量机(SVM)等来进行文本分类。 通过学习NLP-100例,我们可以了解到自然语言处理的基本方法和技术,并且可以利用这些技术来解决相关的自然语言处理问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值