Rohan
Rohan

Reputation: 3334

Creating relations in sentence using chunk tags (not NER) with NLTK | NLP

I am trying to create custom chunk tags and to extract relations from them. Following is the code that takes me to the cascaded chunk tree.

grammar = r"""
  NPH: {<DT|JJ|NN.*>+}          # Chunk sequences of DT, JJ, NN
  PPH: {<IN><NP>}               # Chunk prepositions followed by NP
  VPH: {<VB.*><NP|PP|CLAUSE>+$} # Chunk verbs and their arguments
  CLAUSE: {<NP><VP>}           # Chunk NP, VP
  """
cp = nltk.RegexpParser(grammar)
sentence = [("Mary", "NN"), ("saw", "VBD"), ("the", "DT"), ("cat", "NN"),
    ("sit", "VB"), ("on", "IN"), ("the", "DT"), ("mat", "NN")]


chunked = cp.parse(sentence)

Output -

(S (NPH Mary/NN) saw/VBD (NPH the/DT cat/NN) sit/VB on/IN (NPH the/DT mat/NN))

Now I am trying to extract relations between the NPH tag values with the text in between using the nltk.sem.extract_rels function, BUT it seems to work ONLY on named entities generated with the ne_chunk function.

IN = re.compile(r'.*\bon\b')
for rel in nltk.sem.extract_rels('NPH', 'NPH', chunked,corpus='ieer',pattern = IN):
        print(nltk.sem.rtuple(rel))

This gives the following error -

ValueError: your value for the subject type has not been recognized: NPH

Is there an easy way to use only chunk tags to create relations as I don't really want to retrain the NER model to detect my chunk tags as respective named entities

Thank you!

Upvotes: 7

Views: 923

Answers (1)

mcoav
mcoav

Reputation: 1616

  1. extract_rels (doc) checks that arguments subjclass and objclass are known NE tags, hence the error with NPH.
  2. The easy, ad hoc, way is to rewrite a customized extract_rels function (example below).

    import nltk
    import re
    
    grammar = r"""
      NPH: {<DT|JJ|NN.*>+}          # Chunk sequences of DT, JJ, NN
      PPH: {<IN><NP>}               # Chunk prepositions followed by NP
      VPH: {<VB.*><NP|PP|CLAUSE>+$} # Chunk verbs and their arguments
      CLAUSE: {<NP><VP>}           # Chunk NP, VP
      """
    cp = nltk.RegexpParser(grammar)
    sentence = [("Mary", "NN"), ("saw", "VBD"), ("the", "DT"), ("cat", "NN"),
        ("sit", "VB"), ("on", "IN"), ("the", "DT"), ("mat", "NN")]
    
    chunked = cp.parse(sentence)
    
    IN = re.compile(r'.*\bon\b')
    
    def extract_rels(subjclass, objclass, chunked, pattern):
    
        # padding because this function checks right context
        pairs = nltk.sem.relextract.tree2semi_rel(chunked) + [[[]]] 
    
        reldicts = nltk.sem.relextract.semi_rel2reldict(pairs)
    
        relfilter = lambda x: (x['subjclass'] == subjclass and
                               pattern.match(x['filler']) and
                               x['objclass'] == objclass)
    
    
        return list(filter(relfilter, reldicts))
    
    for e in extract_rels('NPH', 'NPH', chunked, pattern=IN):
        print(nltk.sem.rtuple(e))
    

    Output:

    [NPH: 'the/DT cat/NN'] 'sit/VB on/IN' [NPH: 'the/DT mat/NN']
    

Upvotes: 7

Related Questions