美文网首页
python从零开始构建知识图谱笔记

python从零开始构建知识图谱笔记

作者: jiarf | 来源:发表于2021-01-05 10:43 被阅读0次

    教程:https://zhuanlan.zhihu.com/p/243211697
    前面都进行的好好的,具体的理论因为我已经了解一点了,就不在赘述,教程里面有,直接开始实践,
    前面都没啥问题,直接上代码

    image.png
    image.png
    import re
    import pandas as pd
    import numpy as np
    import bs4
    import requests
    import spacy
    from spacy import displacy
    nlp = spacy.load('en_core_web_sm')
    from spacy.matcher import Matcher 
    from spacy.tokens import Span
    import networkx as nx
    import matplotlib.pyplot as plt
    from tqdm import tqdm
    
    pd.set_option('display.max_colwidth', 200)
    %matplotlib inline
    # import wikipedia sentences
    candidate_sentences = pd.read_csv("wiki_sentences_v2.csv",header=0)
    candidate_sentences.shape
    
    candidate_sentences.sample(7)
    
    doc = nlp("the drawdown process is governed by astm standard d823")
    
    
    for tok in doc:
      print(tok.text, "...", tok.dep_)
    

    好了接下来重点在这里,接下来的一个函数,怎么也对不起行列,出来的答案为空,很奇怪

    def get_entities(sent):
     ## chunk 1
     # 我在这个块中定义了一些空变量。prv tok dep和prv tok text将分别保留句子中前一个单词和前一个单词本身的依赖标签。前缀和修饰符将保存与主题或对象相关的文本。
      ent1 = ""
      ent2 = ""
    
    
      prv_tok_dep = "" # dependency tag of previous token in the sentence
      prv_tok_text = "" # previous token in the sentence
    
    
      prefix = ""
      modifier = ""
    
    
     #############################################################
     
      for tok in nlp(sent):
     ## chunk 2
     # 接下来,我们将遍历句子中的记号。我们将首先检查标记是否为标点符号。如果是,那么我们将忽略它并转移到下一个令牌。如果标记是复合单词的一部分(dependency tag = compound),我们将把它保存在prefix变量中。复合词是由多个单词组成一个具有新含义的单词(例如“Football Stadium”, “animal lover”)。
     # 当我们在句子中遇到主语或宾语时,我们会加上这个前缀。我们将对修饰语做同样的事情,例如“nice shirt”, “big house”
    
    
     # if token is a punctuation mark then move on to the next token
       if tok.dep_ != "punct":
     # check: token is a compound word or not
         if tok.dep_ == "compound":
            prefix = tok.text
     # if the previous word was also a 'compound' then add the current word to it
         if prv_tok_dep == "compound":
              prefix = prv_tok_text + " "+ tok.text
     
     # check: token is a modifier or not
         if tok.dep_.endswith("mod") == True:
            modifier = tok.text
     # if the previous word was also a 'compound' then add the current word to it
         if prv_tok_dep == "compound":
              modifier = prv_tok_text + " "+ tok.text
     
     ## chunk 3
     # 在这里,如果令牌是主语,那么它将作为ent1变量中的第一个实体被捕获。变量如前缀,修饰符,prv tok dep,和prv tok文本将被重置。
       if tok.dep_.find("subj") == True:
            ent1 = modifier +" "+ prefix + " "+ tok.text
            prefix = ""
            modifier = ""
            prv_tok_dep = ""
            prv_tok_text = "" 
    
    
     ## chunk 4
     # 在这里,如果令牌是宾语,那么它将被捕获为ent2变量中的第二个实体。变量,如前缀,修饰符,prv tok dep,和prv tok文本将再次被重置。
       if tok.dep_.find("obj") == True:
            ent2 = modifier +" "+ prefix +" "+ tok.text
     
     ## chunk 5  
     # 一旦我们捕获了句子中的主语和宾语,我们将更新前面的标记和它的依赖标记。
     # update variables
       prv_tok_dep = tok.dep_
       prv_tok_text = tok.text
     #############################################################
       return [ent1.strip(), ent2.strip()]
    
    get_entities("the film had 200 patents")
    

    这里上面教程那个函数的空格对其是有点问题好像,,换这个函数就行:https://gist.github.com/prateekjoshi565/6833da973d65338216d0f6b99755d120,韩被我改了好久,真的是!!!(主要还是自己比较菜)
    对的格式是这个:

    def get_entities(sent):
     ## chunk 1
     # 我在这个块中定义了一些空变量。prv tok dep和prv tok text将分别保留句子中前一个单词和前一个单词本身的依赖标签。前缀和修饰符将保存与主题或对象相关的文本。
        ent1 = ""
        ent2 = ""
    
    
        prv_tok_dep = "" # dependency tag of previous token in the sentence
        prv_tok_text = "" # previous token in the sentence
    
    
        prefix = ""
        modifier = ""
    
    
     #############################################################
     
        for tok in nlp(sent):
     ## chunk 2
     # 接下来,我们将遍历句子中的记号。我们将首先检查标记是否为标点符号。如果是,那么我们将忽略它并转移到下一个令牌。如果标记是复合单词的一部分(dependency tag = compound),我们将把它保存在prefix变量中。复合词是由多个单词组成一个具有新含义的单词(例如“Football Stadium”, “animal lover”)。
     # 当我们在句子中遇到主语或宾语时,我们会加上这个前缀。我们将对修饰语做同样的事情,例如“nice shirt”, “big house”
    
    
     # if token is a punctuation mark then move on to the next token
            if tok.dep_ != "punct":
     # check: token is a compound word or not
                if tok.dep_ == "compound":
                    prefix = tok.text
     # if the previous word was also a 'compound' then add the current word to it
                    if prv_tok_dep == "compound":
                        prefix = prv_tok_text + " "+ tok.text
     
     # check: token is a modifier or not
                if tok.dep_.endswith("mod") == True:
                    modifier = tok.text
     # if the previous word was also a 'compound' then add the current word to it
                    if prv_tok_dep == "compound":
                        modifier = prv_tok_text + " "+ tok.text
     
     ## chunk 3
     # 在这里,如果令牌是主语,那么它将作为ent1变量中的第一个实体被捕获。变量如前缀,修饰符,prv tok dep,和prv tok文本将被重置。
                if tok.dep_.find("subj") == True:
                    ent1 = modifier +" "+ prefix + " "+ tok.text
                    prefix = ""
                    modifier = ""
                    prv_tok_dep = ""
                    prv_tok_text = "" 
    
    
     ## chunk 4
     # 在这里,如果令牌是宾语,那么它将被捕获为ent2变量中的第二个实体。变量,如前缀,修饰符,prv tok dep,和prv tok文本将再次被重置。
                if tok.dep_.find("obj") == True:
                    ent2 = modifier +" "+ prefix +" "+ tok.text
     
     ## chunk 5  
     # 一旦我们捕获了句子中的主语和宾语,我们将更新前面的标记和它的依赖标记。
     # update variables
                prv_tok_dep = tok.dep_
                prv_tok_text = tok.text
     #############################################################
    
    
        return [ent1.strip(), ent2.strip()]
    
    get_entities("the film had 200 patents")
    
    image.png

    在这里因为之前的教程里面的内容数据下载不到,就自己复制了一些,


    image.png

    因为原来读入进去有两列,是因为自己的文件不是csv的,现在,直接做一个excel,另存为--其他格式,然后就可以保存为csv文件了,读入进去就正常很多了。
    因为这里文件没法上传到简书,所以就给大家看看。还是很简单能做出来的。。。

    达到了预期效果,我们对数据集中的句子使用这个函数,提取这些句子中的实体对:

    image.png image.png

    好像和正确的不太一样


    image.png

    原来是这样,因为我的数据只有五句话,没有人家的多,所以根本没有十个到二十个,所以为空,接着我把他调小,就可以了,看起来还行,
    原文中还有,


    image.png

    “如你所见,在这些实体对中有一些代词,如we, it, she等。我们希望用专有名词或名词来代替。也许我们可以进一步改进get entities()函数来过滤代词。但是指代消解是比较高级的技术,现在,让我们让它保持原样,继续到关系提取部分。”
    所以这个后来在看看指代消解技术。

    关系抽取Relation / Predicate Extraction

    “句子中捕获这样的谓词。在这里,我使用了spaCy的基于规则的匹配”



    绝望了,这篇老是对不齐,但是这句还好不难对齐

    #抽提句子关系,,V
    def get_relation(sent):
    
    
        doc = nlp(sent)
    
    
     # Matcher class object 
        matcher = Matcher(nlp.vocab)
    
    
     #define the pattern 
        pattern = [{'DEP':'ROOT'}, 
                {'DEP':'prep','OP':"?"},
                {'DEP':'agent','OP':"?"},  
                {'POS':'ADJ','OP':"?"}] 
    
    
        matcher.add("matching_1", None, pattern) 
    
    
        matches = matcher(doc)
        k = len(matches) - 1
    
    
        span = doc[matches[k][1]:matches[k][2]] 
    
    
        return(span.text)
    

    函数中定义的模式试图找到句子中的词根或主要动词。一旦确定了词根,该模式就会检查它后面是介词(prep)还是代理词。如果是,则将其添加到根词中。试试一下这个函数:

    get_relation("John completed the task")
    
    image.png

    没得问题了。
    用在我们的数据集上:
    对了人家的数据有名字sentence所以是这样的:

    relations = [get_relation(i) for i in tqdm(candidate_sentences['sentence'])]
    
    
    pd.Series(relations).value_counts()[:50]
    

    但是我是自己做的,所以没有名字,都把这个名字删掉就行。


    image.png
    relations = [get_relation(i) for i in tqdm(candidate_sentences)]
    
    pd.Series(relations).value_counts()[:2]
    
    image.png

    但是这个函数可能需要改改,因为我的数据及的结果只有一个is
    以下是我的数据集,可以看出来绝对不止一个is是动词,


    image.png

    可能 因为作者的数据集都是主谓宾这样的形式,但是我们的还加了前置和倒装什么的,不只是主谓宾,还有主谓的,他就识别不好,

    5、构建知识图谱Build a Knowledge Graph

    最后,我们将从提取的实体(主语-宾语对)和谓词(实体之间的关系)创建知识图。

    让我们创建一个实体和谓词的dataframe:

    # extract subject
    source = [i[0] for i in entity_pairs] 
    # extract object
    target = [i[1] for i in entity_pairs] 
    
    
    kg_df = pd.DataFrame({'source':source, 'target':target, 'edge':relations})  
    # create a directed-graph from a dataframe
    G=nx.from_pandas_edgelist(kg_df, "source", "target",                           edge_attr=True, create_using=nx.MultiDiGraph())  
    plt.figure(figsize=(12,12))
    
    
    pos = nx.spring_layout(G)
    nx.draw(G, with_labels=True, node_color='skyblue', edge_cmap=plt.cm.Blues, pos = pos)
    plt.show()
    

    但是因为作者的数据集比较大,所以还需要重新提出来看,但是我的这个哈哈哈就不需要了,太少了实在是。


    image.png

    END!!!!

    相关文章

      网友评论

          本文标题:python从零开始构建知识图谱笔记

          本文链接:https://www.haomeiwen.com/subject/khlioktx.html