• 8.词袋和词向量模型


    1.非结构化数据转换为词袋和词向量模型

    文本数据(非结构化数据)转换成计算机能够计算的数据。有两种常用的模型:词袋和词向量模型。

    2.词袋模型(Bag of Words Model)

    词袋模型看起来好像一个口袋把所有词都装进去,但却不完全如此。在自然语言处理和信息检索中作为一种简单假设,词袋模型把文本(段落或者文档)被看作是无序的词汇集合,忽略语法甚至是单词的顺序,把每一个单词都进行统计,同时计算每个单词出现的次数,常常被用在文本分类中,如贝叶斯算法、LDA 和 LSA 等。

    对于 for 循环多次直接用到列表推导式。在 Python 中,列表推导式的效率比 for 快很多,尤其在数据量大的时候效果更明显.

    2.1 使用jieba进行词袋化

    import jieba
    #定义停用词、标点符号
    punctuation = [",","。", ":", ";", "?"]
    #定义语料
    content = ["机器学习带动人工智能飞速的发展。",
               "深度学习带动人工智能飞速的发展。",
               "机器学习和深度学习带动人工智能飞速的发展。"
              ]
    # 对语料进行分词
    segs_1 = [jieba.lcut(con) for con in content]
    print(segs_1)
    
    #去掉停止词
    tokenized = []
    for sentence in segs_1:
        words = []
        for word in sentence:
            if word not in punctuation:
                words.append(word)
        tokenized.append(words)
    print("\n去除停止词后:",tokenized)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    # 把所有的分词结果放到一个袋子(List)里面,也就是取并集,再去重,获取对应的特征词。
    #求并集
    bag_of_words = [ x for item in segs_1 for x in item if x not in punctuation]
    print(bag_of_words)
    
    #去重
    bag_of_words = list(set(bag_of_words))
    print(bag_of_words)
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    # 以去重后的特征词顺序和去除停止词后的分词进行词袋化
    bag_of_word2vec = []
    for sentence in tokenized:
        tokens = [1 if token in sentence else 0 for token in bag_of_words ]
        bag_of_word2vec.append(tokens)
    print(bag_of_word2vec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    词袋数据可作为分类/预测/深度模型 的输入数据。

    2.2 Gensim 构建词袋模型

    import jieba
    #定义停用词、标点符号
    punctuation = [",","。", ":", ";", "?"]
    #定义语料
    content = ["机器学习带动人工智能飞速的发展。",
               "深度学习带动人工智能飞速的发展。",
               "机器学习和深度学习带动人工智能飞速的发展。"
              ]
    # 对语料进行分词
    segs_1 = [jieba.lcut(con) for con in content]
    print(segs_1)
    
    #去掉停止词
    tokenized = []
    for sentence in segs_1:
        words = []
        for word in sentence:
            if word not in punctuation:
                words.append(word)
        tokenized.append(words)
    print("\n去除停止词后:",tokenized)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    from gensim import corpora
    import gensim
    #tokenized是去标点之后的
    dictionary = corpora.Dictionary(tokenized)
    
    #保存词典到内存中
    dictionary.save('deerwester.dict') 
    # dictionary2 = corpora.Dictionary.load('deerwester.dict')#加载词典
    
    print(dictionary)
    
    print(dictionary.token2id)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    # 函数 doc2bow(),作用只是计算每个不同单词的出现次数,将单词转换为其整数单词 id 并将结果作为稀疏向量返回。
    
    corpus = [dictionary.doc2bow(sentence) for sentence in segs_1]
    print(corpus )
    
    • 1
    • 2
    • 3
    • 4

    词袋数据可作为分类/预测/深度模型 的输入数据。

    3.词向量 (Word Embedding)

    深度学习带给自然语言处理最令人兴奋的突破是词向量(Word Embedding)技术。词向量技术是将词语转化成为稠密向量。在自然语言处理应用中,词向量作为机器学习、深度学习模型的特征进行输入。因此,最终模型的效果很大程度上取决于词向量的效果。

    给词向量一个定义,词向量就是要用某个固定维度的向量去表示单词。也就是说要把单词变成固定维度的向量,作为机器学习(Machine Learning)或深度学习模型的特征向量输入。

    3.1 Word2Vec

    这个模型是如何定义数据的输入和输出呢?一般分为CBOW(Continuous Bag-of-Words 与Skip-Gram两种模型。CBOW模型的训练输入是某一个特征词的上下文相关的词对应的词向量,而输出就是这特定的一个词的词向量。 Skip-Gram模型和CBOW的思路是反着来的,即输入是特定的一个词的词向量,而输出是特定词对应的上下文词向量。CBOW对小型数据库比较合适,而Skip-Gram在大型语料中表现更好。

    • 过程:
      • 查看相关模型:词袋,Word2Vec,Doc2Vec【查文档】
      • 加载并预处理训练和测试语料库(请参阅语料库)
      • 使用训练语料库训练Word2Vec模型模型
      • 演示如何将训练后的模型用于推断向量
      • 评估模型
      • 在测试语料库上测试模型

    Word2Vec解决了词袋模型的第二个缺点(词袋模型不会尝试学习基础单词的含义。)。

    Word2Vec是一种较新的模型,该模型使用浅层神经网络将单词嵌入到低维向量空间中。结果是一组词向量,其中在向量空间中靠在一起的向量根据上下文具有相似的含义,而彼此远离的词向量具有不同的含义。例如,strong和powerful会彼此靠近,strong并且Paris会相对较远。Word2Vec模型,我们可以计算文档中每个单词的向量。

    该模型有两个版本,并且Word2Vec 类同时实现了这两个版本:

    • Skip-grams (SG)【已知中心词预测周围词。】
    • Continuous-bag-of-words连续词袋(CBOW)【已知周围词预测中心词。】
    from gensim.models import Word2Vec  
    import jieba
    #定义停用词、标点符号
    punctuation = [",","。", ":", ";", ".", "'", '"', "’", "?", "/", "-", "+", "&", "(", ")"]
    sentences = [
    "长江是中国第一大河,干流全长6397公里(以沱沱河为源),一般称6300公里。流域总面积一百八十余万平方公里,年平均入海水量约九千六百余亿立方米。以干流长度和入海水量论,长江均居世界第三位。",
    "黄河,中国古代也称河,发源于中华人民共和国青海省巴颜喀拉山脉,流经青海、四川、甘肃、宁夏、内蒙古、陕西、山西、河南、山东9个省区,最后于山东省东营垦利县注入渤海。干流河道全长5464千米,仅次于长江,为中国第二长河。黄河还是世界第五长河。",
    "黄河,是中华民族的母亲河。作为中华文明的发祥地,维系炎黄子孙的血脉.是中华民族民族精神与民族情感的象征。",
    "黄河被称为中华文明的母亲河。公元前2000多年华夏族在黄河领域的中原地区形成、繁衍。",
    "在兰州的“黄河第一桥”内蒙古托克托县河口镇以上的黄河河段为黄河上游。",
    "黄河上游根据河道特性的不同,又可分为河源段、峡谷段和冲积平原三部分。 ",
    "黄河,是中华民族的母亲河。"
    ]
    
    # 去标点符号(注:这里并没用进行去除停止词,完整的步骤应包括去除停止词)
    sentences = [jieba.lcut(sen) for sen in sentences]
    tokenized = []
    for sentence in sentences:
        words = []
        for word in sentence:
            if word not in punctuation:          
                words.append(word)
        tokenized.append(words)
    # print(sentences)
    print(tokenized)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    # 增加ID: 当然,也可以不进行此步骤,因为列表本身就有下标索引。
    # from gensim import corpora
    # dictionary = corpora.Dictionary(tokenized)
    # print(dictionary)
    # print(dictionary.token2id)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    # 
    """
    sg=1 是 skip-gram 算法,对低频词敏感;默认 sg=0 为 CBOW 算法。
    size 是输出词向量的维数,值太小会导致词映射因为冲突而影响结果,值太大则会耗内存并使算法计算变慢,一般值取为100到200之间。
    window 是句子中当前词与目标词之间的最大距离,3表示在目标词前看3-b 个词,后面看 b 个词(b 在0-3之间随机)。
    min_count 是对词进行过滤,频率小于 min-count 的单词则会被忽视,默认值为5。
    negative 和 sample 可根据训练结果进行微调,sample 表示更高频率的词被随机下采样到所设置的阈值,默认值为 1e-3。
    hs=1 表示层级 softmax 将会被使用,默认 hs=0 且 negative 不为0,则负采样将会被选择使用。
    """
    model = Word2Vec(tokenized, sg=1, size=100,  window=5,  min_count=2,  negative=1, sample=0.001, hs=1, workers=4)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    model.save('model')  #保存模型
    model = Word2Vec.load('model')   #加载模型
    
    • 1
    • 2
    # 模型训练好之后,接下来就可以使用模型,可以用来计算句子或者词的相似性、最大匹配程度等。
    
    print(model.similarity('黄河', '黄河')) #黄河和黄河自己的相似度
    print(model.similarity('黄河', '长江'))#黄河和长江的相似度
    
    • 1
    • 2
    • 3
    • 4
    # 预测最接近的词,预测与黄河和母亲河最接近,而与长江不接近的词:注:返回的每个词后面是相似度大小
    print(model.most_similar(positive=['黄河', '母亲河'], negative=['长江']))
    
    # [(词语,相似度大小),(词语,相似度大小),(词语,相似度大小),(词语,相似度大小),]就作为一个可以替代原来的词袋模型的训练数据。
    
    • 1
    • 2
    • 3
    • 4

    3.2 Doc2Vec

    Doc2Vec 是 Mikolov 在 Word2Vec 基础上提出的另一个用于计算长文本向量的工具。在 Gensim 库中,Doc2Vec 与 Word2Vec 都极为相似。但两者在对输入数据的预处理上稍有不同,Doc2vec 接收一个由 LabeledSentence 对象组成的迭代器作为其构造函数的输入参数。其中,LabeledSentence 是 Gensim 内建的一个类,它接收两个 List 作为其初始化的参数:word list 和 label list。

    Doc2Vec 也包括两种实现方式:DBOW(Distributed Bag of Words)和 DM (Distributed Memory)。DBOW 和 DM 的实现,二者在 gensim 库中的实现用的是同一个方法,该方法中参数 dm = 0 或者 dm=1 决定调用 DBOW 还是 DM。Doc2Vec 将文档语料通过一个固定长度的向量表达。

    • 过程:
      • 查看相关模型:词袋,Word2Vec,Doc2Vec【查文档】
      • 加载并预处理训练和测试语料库(请参阅语料库)
      • 使用训练语料库训练Doc2Vec模型模型
      • 演示如何将训练后的模型用于推断向量
      • 评估模型
      • 在测试语料库上测试模型

    Word2Vec模型可以计算文档中每个单词的向量。但是,如果我们要为整个文档计算一个向量,该怎么办?我们可以对文档中每个单词的向量进行平均-尽管这是快速而粗略的,但它通常很有用。但是,有更好的方法…那就是Doc2Vec,基本思想是:就像文档中有另一个像单词一样的浮动单词矢量一样起作用,它有助于所有训练预测,并且像其他单词矢量一样进行更新,但是我们将其称为doc矢量。

    • Doc2Vec有两种实现:

      • 段落向量-分布式内存(PV-DM)
      • 段落向量-单词分布袋(PV-DBOW)
    for c in tokenized:
        print(c)
    
    • 1
    • 2
    #定义数据预处理类,作用是给每个文章添加对应的标签
    from gensim.models.doc2vec import Doc2Vec,LabeledSentence
    doc_labels = ["长江","黄河","黄河","黄河","黄河","黄河","黄河"]
    punctuation = [",","。", ":", ";", "?"]
    
    #定义语料
    
    
    class LabeledLineSentence(object):
        def __init__(self, doc_list, labels_list):
            self.labels_list = labels_list
            self.doc_list = doc_list
        def __iter__(self):
            for idx, doc in enumerate(self.doc_list):
                yield LabeledSentence(words=doc,tags=[self.labels_list[idx]])
    
    # model = Doc2Vec(content,dm=1, size=100, window=8, min_count=5, workers=4)
    # model.save('model')
    # model = Doc2Vec.load('model')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    # 上面定义好了数据预处理函数,我们将 Word2Vec 中分词去标点后的数据,进行转换:
    iter_data = LabeledLineSentence(tokenized, doc_labels)
    
    • 1
    • 2
    # 定义模型参数
    model = Doc2Vec(dm=1, size=100, window=8, min_count=5, workers=4)
    model.build_vocab(iter_data)
    
    • 1
    • 2
    • 3
    # 训练模型, 设置迭代次数1000次,start_alpha 为开始学习率,end_alpha 与 start_alpha 线性递减
    model.train(iter_data,total_examples=model.corpus_count,epochs=1000,start_alpha=0.01,end_alpha =0.001)
    
    • 1
    • 2
    #根据标签找最相似的,这里只有黄河和长江,所以结果为长江,并计算出了相似度
    print(model.docvecs.most_similar('黄河'))
    
    
    # 对黄河和长江标签做相似性计算:
    print(model.docvecs.similarity('黄河','长江'))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.3 Fasttext

    gensim 中Fasttext 模型架构和Word2Vec的模型架构差几乎一样,只不过在模型词的输入部分使用了词的n-gram的特征。这里需要讲解一下n-gram特征的含义。举个例子,如果原词是一个很长的词:你吃了吗。jieba分词结果为[“你”,“吃了”,“吗”]。

    • unigram(1-gram)的特征:[“你”,“吃了”,“吗”]
    • bigram(2-gram) 的特征: [“你吃了”,“吃了吗”]

    所以发现没,n-gram的意思将词中连续的n个词连起来组成一个单独的词。
    如果使用unigram和bigram的特征,词的特征就会变成:[“你”,“吃了”,“吗”,“你吃了”,“吃了吗”]这么一长串。使用n-gram的词向量使得Fast-text模型可以很好的解决未登录词(OOV——out-of-vocabulary)的问题。

  • 相关阅读:
    基于开源IM即时通讯框架MobileIMSDK:RainbowChat v11.5版已发布
    护眼灯色温多少最好?儿童护眼灯色温范围多少
    DAC的简单应用
    Java面试题基础第十一天
    springboot236基于springboot在线课程管理系统的设计与实现
    CSP-S2023 总结
    vue3触发store的时机和使用store中的变量
    flutter Widget index
    uboot启动参数详解和一些细节
    L2-048 寻宝图(PTA)
  • 原文地址:https://blog.csdn.net/qq_42658739/article/details/127643546