Me gustaría saber si el tokenizador de espacios podría convertir en token las palabras usando solo la regla del "espacio". Por ejemplo:

sentence= "(c/o Oxford University )"

Normalmente, usando la siguiente configuración de espacio:

nlp = spacy.load("en_core_news_sm")
doc = nlp(sentence)
for token in doc:
   print(token)

El resultado sería:

 (
 c
 /
 o
 Oxford
 University
 )

En cambio, me gustaría una salida como la siguiente (usando spacy):

(c/o 
Oxford 
University
)

¿Es posible obtener un resultado como este usando spacy?

1
sergio zavota 5 dic. 2020 a las 21:04

2 respuestas

La mejor respuesta

Cambiemos nlp.tokenizer con un Tokenizer personalizado con {{X2} } regex:

import re
import spacy
from spacy.tokenizer import Tokenizer

nlp = spacy.load('en_core_web_sm')
text = "This is it's"
print("Before:", [tok for tok in nlp(text)])

nlp.tokenizer = Tokenizer(nlp.vocab, token_match=re.compile(r'\S+').match)
print("After :", [tok for tok in nlp(text)])

Before: [This, is, it, 's]
After : [This, is, it's]

Puede ajustar aún más Tokenizer agregando reglas personalizadas de sufijos, prefijos e infijos.

Una forma alternativa y más detallada sería averiguar por qué el token it's se divide como lo está con nlp.tokenizer.explain():

import spacy
from spacy.tokenizer import Tokenizer
nlp = spacy.load('en_core_web_sm')
text = "This is it's. I'm fine"
nlp.tokenizer.explain(text)

Descubrirás que la división se debe a las reglas de SPECIAL:

[('TOKEN', 'This'),
 ('TOKEN', 'is'),
 ('SPECIAL-1', 'it'),
 ('SPECIAL-2', "'s"),
 ('SUFFIX', '.'),
 ('SPECIAL-1', 'I'),
 ('SPECIAL-2', "'m"),
 ('TOKEN', 'fine')]

Que podría actualizarse para eliminar "es" de excepciones como:

exceptions = nlp.Defaults.tokenizer_exceptions
filtered_exceptions = {k:v for k,v in exceptions.items() if k!="it's"}
nlp.tokenizer = Tokenizer(nlp.vocab, rules = filtered_exceptions)
[tok for tok in nlp(text)]

[This, is, it's., I, 'm, fine]

O elimine la división en el apóstrofe por completo:

filtered_exceptions = {k:v for k,v in exceptions.items() if "'" not in k}
nlp.tokenizer = Tokenizer(nlp.vocab, rules = filtered_exceptions)
[tok for tok in nlp(text)]

[This, is, it's., I'm, fine]

Tenga en cuenta el punto adjunto al token, que se debe a las reglas de sufijo no especificadas.

1
Sergey Bushmanov 6 dic. 2020 a las 12:10

Puede encontrar la solución a esta misma pregunta en los documentos de spaCy: https: // spacy.io/usage/linguistic-features#custom-tokenizer-example. En pocas palabras, crea una función que toma una cadena text y devuelve un objeto Doc, y luego asigna esa función invocable a nlp.tokenizer:

import spacy
from spacy.tokens import Doc

class WhitespaceTokenizer(object):
    def __init__(self, vocab):
        self.vocab = vocab

    def __call__(self, text):
        words = text.split(' ')
        # All tokens 'own' a subsequent space character in this tokenizer
        spaces = [True] * len(words)
        return Doc(self.vocab, words=words, spaces=spaces)

nlp = spacy.load("en_core_web_sm")
nlp.tokenizer = WhitespaceTokenizer(nlp.vocab)
doc = nlp("What's happened to me? he thought. It wasn't a dream.")
print([t.text for t in doc])
1
Sofie VL 5 dic. 2020 a las 18:46