• 大三学习进度21


    使用anaconda安装jieba十分方便

    jieba是python的一个中文分词库,下面介绍它的使用方法。

    安装

    方式1:
    pip install jieba
    
    方式2:
    先下载 http://pypi.python.org/pypi/jieba/
    然后解压,运行 python setup.py install

    功能

    下面介绍下jieba的主要功能,具体信息可参考github文档:

    分词

    jieba常用的三种模式:

    1. 精确模式,试图将句子最精确地切开,适合文本分析;
    2. 全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;
    3. 搜索引擎模式,在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。

    可使用 jieba.cut 和 jieba.cut_for_search 方法进行分词,两者所返回的结构都是一个可迭代的 generator,可使用 for 循环来获得分词后得到的每一个词语(unicode),或者直接使用 jieba.lcut 以及 jieba.lcut_for_search 返回 list。

    jieba.Tokenizer(dictionary=DEFAULT_DICT) :使用该方法可以自定义分词器,可以同时使用不同的词典。jieba.dt 为默认分词器,所有全局分词相关函数都是该分词器的映射。

    jieba.cut 和 jieba.lcut 可接受的参数如下:

    1. 需要分词的字符串(unicode 或 UTF-8 字符串、GBK 字符串)
    2. cut_all:是否使用全模式,默认值为 False
    3. HMM:用来控制是否使用 HMM 模型,默认值为 True

    jieba.cut_for_search 和 jieba.lcut_for_search 接受 2 个参数:

    1. 需要分词的字符串(unicode 或 UTF-8 字符串、GBK 字符串)
    2. HMM:用来控制是否使用 HMM 模型,默认值为 True

    需要注意的是,尽量不要使用 GBK 字符串,可能无法预料地错误解码成 UTF-8。

    三种分词模式的比较:

    # 全匹配
    seg_list = jieba.cut("今天哪里都没去,在家里睡了一天", cut_all=True)
    print(list(seg_list))  # ['今天', '哪里', '都', '没去', '', '', '在家', '家里', '睡', '了', '一天']
    
    # 精确匹配 默认模式
    seg_list = jieba.cut("今天哪里都没去,在家里睡了一天", cut_all=False)
    print(list(seg_list))  # ['今天', '哪里', '都', '没', '去', ',', '在', '家里', '睡', '了', '一天']
    
    # 精确匹配
    seg_list = jieba.cut_for_search("今天哪里都没去,在家里睡了一天")
    print(list(seg_list))  # ['今天', '哪里', '都', '没', '去', ',', '在', '家里', '睡', '了', '一天']

    自定义词典

    开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词。
    用法: jieba.load_userdict(dict_path)

    dict_path:为自定义词典文件的路径

    词典格式如下:

    一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。

    下面使用一个例子说明一下:

    自定义字典 user_dict.txt:

    大学课程
    深度学习

    下面比较下精确匹配、全匹配和使用自定义词典的区别:

    import jieba
    
    
    test_sent = """
    数学是一门基础性的大学课程,深度学习是基于数学的,尤其是线性代数课程
    """
    
    words = jieba.cut(test_sent)
    print(list(words))
    # ['\n', '数学', '是', '一门', '基础性', '的', '大学', '课程', ',', '深度',
    # '学习', '是', '基于', '数学', '的', ',', '尤其', '是', '线性代数', '课程', '\n']
    
    words = jieba.cut(test_sent, cut_all=True)
    print(list(words))
    # ['\n', '数学', '是', '一门', '基础', '基础性', '的', '大学', '课程', '', '', '深度',
    # '学习', '是', '基于', '数学', '的', '', '', '尤其', '是', '线性', '线性代数', '代数', '课程', '\n']
    
    jieba.load_userdict("userdict.txt")
    words = jieba.cut(test_sent)
    print(list(words))
    # ['\n', '数学', '是', '一门', '基础性', '的', '大学课程', ',', '深度学习', '是',
    # '基于', '数学', '的', ',', '尤其', '是', '线性代数', '课程', '\n']
    
    jieba.add_word("尤其是")
    jieba.add_word("线性代数课程")
    
    words = jieba.cut(test_sent)
    print(list(words))
    # ['\n', '数学', '是', '一门', '基础性', '的', '大学课程', ',', '深度学习', '是',
    # '基于', '数学', '的', ',', '尤其是', '线性代数课程', '\n']

    从上面的例子中可以看出,使用自定义词典与使用默认词典的区别。

    jieba.add_word():向自定义字典中添加词语

     

    关键词提取

    可以基于 TF-IDF 算法进行关键词提取,也可以基于extRank 算法。 TF-IDF 算法与 elasticsearch 中使用的算法是一样的。

    使用 jieba.analyse.extract_tags() 函数进行关键词提取,其参数如下:

    jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())

    1. sentence 为待提取的文本
    2. topK 为返回几个 TF/IDF 权重最大的关键词,默认值为 20
    3. withWeight 为是否一并返回关键词权重值,默认值为 False
    4. allowPOS 仅包括指定词性的词,默认值为空,即不筛选
    5. jieba.analyse.TFIDF(idf_path=None) 新建 TFIDF 实例,idf_path 为 IDF 频率文件

    也可以使用 jieba.analyse.TFIDF(idf_path=None) 新建 TFIDF 实例,idf_path 为 IDF 频率文件。

    基于 TF-IDF 算法的关键词抽取:

    import jieba.analyse
    
    file = "sanguo.txt"
    topK = 12
    content = open(file, 'rb').read()
    
    tags = jieba.analyse.extract_tags(content, topK=topK)
    print(tags)
    # ['玄德', '程远志', '张角', '云长', '张飞', '黄巾', '封谞', '刘焉', '邓茂', '邹靖', '姓名', '招军']
    
    # withWeight=True:将权重值一起返回
    tags = jieba.analyse.extract_tags(content, topK=topK, withWeight=True)
    print(tags)
    # [('玄德', 0.1038549799467099), ('程远志', 0.07787459004363208), ('张角', 0.0722532891360849),
    # ('云长', 0.07048801593691037), ('张飞', 0.060972692853113214), ('黄巾', 0.058227157790330185),
    # ('封谞', 0.0563904127495283), ('刘焉', 0.05470798376886792), ('邓茂', 0.04917692565566038),
    # ('邹靖', 0.04427258239705188), ('姓名', 0.04219704283997642), ('招军', 0.04182041076757075)]

    上面的代码是读取文件,提取出现频率最高的前12个词。

    TF-IDF的原理如下:

    词频 (term frequency, TF) 指的是某一个给定的词语在该文件中出现的次数。这个数字通常会被归一化(一般是词频除以文章总词数)。

    [公式]

    逆向文件频率 (inverse document frequency, IDF) IDF的主要思想是:如果包含词条t的文档越少, IDF越大,则说明词条具有很好的类别区分能力。某一特定词语的IDF,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取对数得到。

    [公式]

    关键词提取所使用逆向文件频率(IDF)文本语料库,当提取的结果不是我们想要的结果时,我们可以自定义IDF文本语料库。

    词性标注

    词性标注主要是标记文本分词后每个词的词性,使用例子如下:

    import jieba
    import jieba.posseg as pseg
    
    # 默认模式
    seg_list = pseg.cut("今天哪里都没去,在家里睡了一天")
    for word, flag in seg_list:
        print(word + " " + flag)
       
    """
    使用 jieba 默认模式的输出结果是:
    我 r
    Prefix dict has been built successfully.
    今天 t
    吃 v
    早饭 n
    了 ul
    """
    
    # paddle 模式
    words = pseg.cut("我今天吃早饭了",use_paddle=True)
    """
    使用 paddle 模式的输出结果是:
    我 r
    今天 TIME
    吃 v
    早饭 n
    了 xc
    """

    paddle模式的词性对照表如下:

    获取词语位置

    将分本分词后,返回每个词和该词在原文中的起始位置,例子如下:

    import jieba
    
    result = jieba.tokenize('今天哪里都没去,在家里睡了一天')
    for tk in result:
        print("word:" + tk[0] +
              " start:" + str(tk[1]) +
              " end:" + str(tk[2]))
        
    """
    word:华为技术有限公司 start:0 end:8
    word:的 start:8 end:9
    word:手机 start:9 end:11
    word:品牌 start:11 end:13
    """
    
    
    # 使用 search 模式
    result = jieba.tokenize('华为技术有限公司的手机品牌', mode="search")
    for tk in result:
        print("word:" + tk[0] +
              " start:" + str(tk[1]) +
              " end:" + str(tk[2]))
    """
    输出:
    word:华为 start:0 end:2
    word:技术 start:2 end:4
    word:有限 start:4 end:6
    word:公司 start:6 end:8
    word:华为技术有限公司 start:0 end:8
    word:的 start:8 end:9
    word:手机 start:9 end:11
    word:品牌 start:11 end:13
    """

    收索引擎

    使用 jieba 和 whoosh 可以实现搜索引擎功能。

    whoosh 是由python实现的一款全文搜索工具包,可以使用 pip 安装它:

    pip install whoosh

    介绍 jieba + whoosh 实现搜索之前,你可以先看下文 whoosh 的简单介绍。

    下面看一个简单的搜索引擎的例子:

    import os
    import shutil
    
    from whoosh.fields import *
    from whoosh.index import create_in
    from whoosh.qparser import QueryParser
    from jieba.analyse import ChineseAnalyzer
    
    
    analyzer = ChineseAnalyzer()
    
    schema = Schema(title=TEXT(stored=True),
                    path=ID(stored=True),
                    content=TEXT(stored=True,
                                 analyzer=analyzer))
    if not os.path.exists("test"):
        os.mkdir("test")
    else:
        # 递归删除目录
        shutil.rmtree("test")
        os.mkdir("test")
    
    idx = create_in("test", schema)
    writer = idx.writer()
    
    writer.add_document(
        title=u"document1",
        path="/tmp1",
        content=u"Tracy McGrady is a famous basketball player, the elegant basketball style of him attract me")
    writer.add_document(
        title=u"document2",
        path="/tmp2",
        content=u"Kobe Bryant is a famous basketball player too , the tenacious spirit of him also attract me")
    writer.add_document(
        title=u"document3",
        path="/tmp3",
        content=u"LeBron James is the player i do not like")
    
    writer.commit()
    searcher = idx.searcher()
    parser = QueryParser("content", schema=idx.schema)
    
    for keyword in ("basketball", "elegant"):
        print("searched keyword ",keyword)
        query= parser.parse(keyword)
        results = searcher.search(query)
        for hit in results:
            print(hit.highlights("content"))
        print("="*50)

    上面代码中,使用 add_document() 把一个文档添加到了 index 中。在这些文档中,搜索含有 “basketball”和 “elegant” 的文档。

    打印结果如下:

    Building prefix dict from the default dictionary ...
    Loading model from cache C:\Users\wyzane\AppData\Local\Temp\jieba.cache
    Loading model cost 0.754 seconds.
    Prefix dict has been built successfully.
    searched keyword  basketball
    McGrady is a famous <b class="match term0">basketball</b> player, the elegant...<b class="match term0">basketball</b> style of him attract me
    Bryant is a famous <b class="match term0">basketball</b> player too , the tenacious
    ==================================================
    searched keyword  elegant
    basketball player, the <b class="match term0">elegant</b> basketball style
    ==================================================

    更换搜索词时:

    for keyword in ("LeBron", "Kobe"):
        print("searched keyword ",keyword)
        query= parser.parse(keyword)
        results = searcher.search(query)
        for hit in results:
            print(hit.highlights("content"))
        print("="*50)

    搜索结果如下:

    Building prefix dict from the default dictionary ...
    Loading model from cache C:\Users\wyzane\AppData\Local\Temp\jieba.cache
    Loading model cost 0.801 seconds.
    Prefix dict has been built successfully.
    searched keyword  LeBron
    <b class="match term0">LeBron</b> James is the player i do not like
    ==================================================
    searched keyword  Kobe
    <b class="match term0">Kobe</b> Bryant is a famous basketball player too , the tenacious
    ==================================================

    上面是搜索英文,下面展示下搜索中文。

    添加下面的文档数据:

    writer.add_document(
        title=u"document1",
        path="/tmp1",
        content=u"麦迪是一位著名的篮球运动员,他飘逸的打法深深吸引着我")
    writer.add_document(
        title=u"document2",
        path="/tmp2",
        content=u"科比是一位著名的篮球运动员,他坚韧的精神深深的感染着我")
    writer.add_document(
        title=u"document3",
        path="/tmp3",
        content=u"詹姆斯是我不喜欢的运动员")

    执行搜索:

    for keyword in ("篮球", "麦迪"):
        print("searched keyword ",keyword)
        query= parser.parse(keyword)
        results = searcher.search(query)
        for hit in results:
            print(hit.highlights("content"))
        print("="*50)

    结果如下:

    Building prefix dict from the default dictionary ...
    Loading model from cache C:\Users\wyzane\AppData\Local\Temp\jieba.cache
    Loading model cost 0.780 seconds.
    Prefix dict has been built successfully.
    searched keyword  篮球
    麦迪是一位著名的<b class="match term0">篮球</b>运动员,他飘逸的打法深深吸引着我
    科比是一位著名的<b class="match term0">篮球</b>运动员,他坚韧的精神深深的感染着我
    ==================================================
    searched keyword  麦迪
    <b class="match term0">麦迪</b>是一位著名的篮球运动员,他飘逸的打法深深吸引着我
    ==================================================

    上面就简单介绍了 jieba + whoosh 实现搜索引擎的例子。其实要实现上面的搜索功能,在 elasticsearch 中可以更加简单,有兴趣的同学可以了解一下。

     

    whoosh

    下面介绍下 whoosh 的使用。

    whoosh 官方文档为:

    使用 whoosh 之前,需要先定义 index 对象,同时创建 schema对象 与 index 对应。schema中包含一列字段,这些字段存放在 index 中。每个字段都是文档中的一部分信息,例如标题和文本内容。字段能被搜索或者存储。

    定义一个 schema,由两个字段:

    from whoosh.fields import Schema, STORED, ID, KEYWORD, TEXT
    
    schema = Schema(title=TEXT(stored=True), content=TEXT,
                    path=ID(stored=True), tags=KEYWORD, 
                    icon=STORED)

    我们仅需要创建一次 schema,当创建索引时,schema 会被序列化并与 index 保存在一起。

    当创建 schema 对象时,需要指定字段名和其对应的类型,在 whoosh.fields 下,由如下类型:

    ID:该类型索引字段的整个值作为一个单位类索引,而不是拆分成多个词
    TEXT:该类型适用于文本数据的正文,它为文本建立索引并存储术语位置以允许短语搜索
    NUMERIC:数值类型,可以存储整数或者浮点数
    BOOLEANBoolean类型
    DATETIME:适用于 datetime 对象
    KEYWORD:适用于空格或者标点分割的关键字,类型数据能被索引和搜索但是不支持短语搜索(为了节省空间)
    STORED:与文档存储在一起而不是与索引,该类型的数据不能被索引和搜索

    schema对象创建完成后,可以使用 create_in 函数创建索引:

    import os.path
    
    from whoosh.index import create_in
    from whoosh.fields import Schema, STORED, ID, KEYWORD, TEXT
    
    schema = Schema(title=TEXT(stored=True), content=TEXT,
                    path=ID(stored=True), tags=KEYWORD, 
                    icon=STORED)
    
    if not os.path.exists("index"):
        os.mkdir("index")
    ix = create_in("index", schema)

    创建 index 时,会创建一个存储对象来保存 index 信息。

    通常,存储对象都会是 FileStorage,一种使用文件来存储索引的存储介质。

    创建索引后,也可以通过 open_dir() 来打开索引:

    from whoosh.index import open_dir
    
    ix = open_dir("index")

    创建好 index 对象后,我们可以往里面添加文档。writer() 方法会返回一个 IndexWriter 对象,使用它可以向 index 中添加文档:

    writer = ix.writer()
    writer.add_document(title=u"My document", content=u"This is my document!",
                        path=u"/a", tags=u"first short", icon=u"/icons/star.png")
    writer.add_document(title=u"Second try", content=u"This is the second example.",
                        path=u"/b", tags=u"second short", icon=u"/icons/sheep.png")
    writer.add_document(title=u"Third time's the charm", content=u"Examples are many.",
                        path=u"/c", tags=u"short", icon=u"/icons/book.png")
    writer.commit()  # 保存文档到索引中

    添加文档时,没有必要对所有字段都添加值;能被索引的 TEXT 字段必须要传入一个 unicode 类型的值,仅仅被存储而不用来索引的字段可以传入任何可被序列化的对象。

    文档存储到 index 后,就可以进行索引了,索引之前首先要创建一个 search 对象:

    searcher = ix.searcher()

    可以使用 with 语句,以便使 search 对象自动关闭,也可以使用 try … finally:

    with ix.searcher() as searcher:
        ...
        
        
    try:
        searcher = ix.searcher()
        ...
    finally:
        searcher.close()

    search 对象的 search() 方法需要传入一个 Query 对象。可以直接钩爪一个 Query 对象,也可以使用QueryParse构造一个 Query 对象。将 Query 对象传入 search() 方法中,可以得到一个 Results 对象。

    from whoosh.query import *
    myquery = And([Term("content", u"apple"), Term("content", "bear")])
    
    # 或者使用
    from whoosh.qparser import QueryParser
    parser = QueryParser("content", ix.schema)
    myquery = parser.parse(querystring)
    
    
    results = searcher.search(myquery)
  • 相关阅读:
    CentOS+Nginx+PHP+MySQL详细配置(图解)
    linux下MySQL安装登录及操作
    hdu 1059 多重背包
    hdu 1754 单点更新
    poj 3264 RMQ 水题
    hdu 1114 基础完全背包
    hdu 3466 排序01背包
    poj 2923 状压dp+01背包
    hdu 2639 第k大01背包
    hdu 2184 01背包变形
  • 原文地址:https://www.cnblogs.com/hhw12345/p/14159595.html
Copyright © 2020-2023  润新知