2015-09-01 7 views
8

Dare una frase di input, che ha BIO chunk tags:Come estrarre i pezzi dalle frasi BIO Chunked? - pitone

[('Che', 'B-NP'), ('è', 'B-VP'), ('la', ' B-NP '), (' velocità ', ' I-NP '), (' of ',' B-PP '), (' an ',' B-NP '), (' vuoto ',' I -NP '), (' ingoiare', 'i-NP'), ('?', 'O')]

avrei bisogno di estrarre le frasi rilevanti, ad es se voglio estrarre 'NP', avrei bisogno di estrarre i frammenti di tuple che contengono B-NP e I-NP.

[out]:

[('What', '0'), ('the airspeed', '2-3'), ('an unladen swallow', '5-6-7')] 

(Nota: i numeri nelle tuple estratto rappresentano l'indice di token.)

ho provato l'estrazione utilizzando il seguente codice:

def extract_chunks(tagged_sent, chunk_type): 
    current_chunk = [] 
    current_chunk_position = [] 
    for idx, word_pos in enumerate(tagged_sent): 
     word, pos = word_pos 
     if '-'+chunk_type in pos: # Append the word to the current_chunk. 
      current_chunk.append((word)) 
      current_chunk_position.append((idx)) 
     else: 
      if current_chunk: # Flush the full chunk when out of an NP. 
       _chunk_str = ' '.join(current_chunk) 
       _chunk_pos_str = '-'.join(map(str, current_chunk_position)) 
       yield _chunk_str, _chunk_pos_str 
       current_chunk = [] 
       current_chunk_position = [] 
    if current_chunk: # Flush the last chunk. 
     yield ' '.join(current_chunk), '-'.join(current_chunk_position) 


tagged_sent = [('What', 'B-NP'), ('is', 'B-VP'), ('the', 'B-NP'), ('airspeed', 'I-NP'), ('of', 'B-PP'), ('an', 'B-NP'), ('unladen', 'I-NP'), ('swallow', 'I-NP'), ('?', 'O')] 
print (list(extract_chunks(tagged_sent, chunk_type='NP'))) 

Ma quando ho un blocco adiacente dello stesso tipo:

tagged_sent = [('The', 'B-NP'), ('Mitsubishi', 'I-NP'), ('Electric', 'I-NP'), ('Company', 'I-NP'), ('Managing', 'B-NP'), ('Director', 'I-NP'), ('ate', 'B-VP'), ('ramen', 'B-NP')] 

print (list(extract_chunks(tagged_sent, chunk_type='NP'))) 

Produce questo:

[('The Mitsubishi Electric Company Managing Director', '0-1-2-3-4-5'), ('ramen', '7')] 

Invece della desiderata:

[('The Mitsubishi Electric Company', '0-1-2-3'), ('Managing Director', '4-5'), ('ramen', '7')] 

come può essere risolto dal codice di cui sopra?

Diverso da come è fatto dal codice sopra, c'è una soluzione migliore per estrarre i blocchi desiderati di uno specifico chunk_type?

risposta

1
def extract_chunks(tagged_sent, chunk_type): 
    grp1, grp2, chunk_type = [], [], "-" + chunk_type 
    for ind, (s, tp) in enumerate(tagged_sent): 
     if tp.endswith(chunk_type): 
      if not tp.startswith("B"): 
       grp2.append(str(ind)) 
       grp1.append(s) 
      else: 
       if grp1: 
        yield " ".join(grp1), "-".join(grp2) 
       grp1, grp2 = [s], [str(ind)] 
    yield " ".join(grp1), "-".join(grp2) 

uscita:

In [2]: l = [('The', 'B-NP'), ('Mitsubishi', 'I-NP'), ('Electric', 'I-NP'), ('Company', 'I-NP'), ('Managing', 'B-NP'), 
    ...:    ('Director', 'I-NP'), ('ate', 'B-VP'), ('ramen', 'B-NP')] 

In [3]: list(extract_chunks(l, "NP")) 
Out[3]: 
[('The Mitsubishi Electric Company', '0-1-2-3'), 
('Managing Director', '4-5'), 
('ramen', '7')] 

In [4]: l = [('What', 'B-NP'), ('is', 'B-VP'), ('the', 'B-NP'), ('airspeed', 'I-NP'), ('of', 'B-PP'), ('an', 'B-NP'), ('unladen', 'I-NP'), ('swallow', 'I-NP'), ('?', 'O')] 

In [5]: list(extract_chunks(l, "NP")) 
Out[5]: [('What', '0'), ('the airspeed', '2-3'), ('an unladen swallow', '5-6-7')] 
0

lo farei in questo modo:

import re 
def extract_chunks(tagged_sent, chunk_type): 
    # compiles the expression we want to match 
    regex = re.compile(chunk_type) 

    # filters matched items in a dictionary whose keys are the matched indexes 
    first_step = {index_:tag[0] for index_, tag in enumerate(tagged_sent) if regex.findall(tag[1])} 

    # builds list of lists following output format 
    second_step = [] 
    for key_ in sorted(first_step.keys()): 
     if second_step and int(second_step [len(second_step)-1][1].split('-')[-1]) == key_ -1:   
      second_step[len(second_step)-1][0] += ' {0}'.format(first_step[key_]) 
      second_step[len(second_step)-1][1] += '-{0}'.format(str(key_)) 
     else: 
      second_step.append([first_step[key_], str(key_)]) 

    # builds output in final format 
    return [tuple(item) for item in second_step] 

È possibile adattare in modo da utilizzare i generatori invece di costruire l'intera produzione in memoria come sto facendo e refactory per migliorare le prestazioni (io sono in un affrettatevi quindi il codice è ben lungi dall'essere ottimale).

Spero che aiuti!

2

Prova questo, estrarrà tutti i tipi di blocchi con gli indici delle loro rispettive parole.

def extract_chunks(tagged_sent, chunk_type='NP'): 
    out_sen = [] 
    for idx, word_pos in enumerate(tagged_sent): 
     word,bio = word_pos 
     boundary,tag = bio.split("-") if "-" in bio else ('','O') 
     if tag != chunk_type:continue 
     if boundary == "B": 
      out_sen.append([word, str(idx)]) 
     elif boundary == "I": 
      out_sen[-1][0] += " "+ word 
      out_sen[-1][-1] += "-"+ str(idx) 
     else: 
      out_sen.append([word, str(idx)]) 
    return out_sen 

Demo:

>>> tagged_sent = [('The', 'B-NP'), ('Mitsubishi', 'I-NP'), ('Electric', 'I-NP'), ('Company', 'I-NP'), ('Managing', 'B-NP'), ('Director', 'I-NP'), ('ate', 'B-VP'), ('ramen', 'B-NP')] 
>>> output_sent = extract_chunks(tagged_sent) 
>>> print map(tuple, output_sent) 
[('The Mitsubishi Electric Company', '0-1-2-3'), ('Managing Director', '4-5'), ('ramen', '7')] 
Problemi correlati