Closed davidggphy closed 3 years ago
Hi @davidggphy, thanks for the kind words!
Making the fuzzy matching in spaczz case-sensitive is pretty straightforward. If you're using the SpaczzRuler
you can either control this on the ruler-level or the pattern-level as shown below:
Pattern-Level
import spacy
from spaczz.pipeline import SpaczzRuler
nlp = spacy.blank("en")
text = "testing, TESTING"
doc = nlp(text)
patterns = [
{
"label": "TEST",
"pattern": "testing",
"type": "fuzzy",
"kwargs": {"ignore_case": "False"},
},
{
"label": "TEST",
"pattern": "TESTING",
"type": "fuzzy",
"kwargs": {"ignore_case": "False"},
},
]
ruler = SpaczzRuler(nlp)
ruler.add_patterns(patterns)
doc = ruler(doc)
for ent in doc.ents:
print((ent.text, ent.start, ent.end, ent.label_, ent._.spaczz_ratio))
('testing', 0, 1, 'TEST', 100)
('TESTING', 2, 3, 'TEST', 100)
Ruler-Level
import spacy
from spaczz.pipeline import SpaczzRuler
nlp = spacy.blank("en")
text = "testing, TESTING"
doc = nlp(text)
patterns = [
{
"label": "TEST",
"pattern": "testing",
"type": "fuzzy",
},
{
"label": "TEST",
"pattern": "TESTING",
"type": "fuzzy",
},
]
ruler = SpaczzRuler(nlp, fuzzy_defaults={"ignore_case": False})
ruler.add_patterns(patterns)
doc = ruler(doc)
for ent in doc.ents:
print((ent.text, ent.start, ent.end, ent.label_, ent._.spaczz_ratio))
('testing', 0, 1, 'TEST', 100)
('TESTING', 2, 3, 'TEST', 100)
For handling accents I would recommend two approaches. One is to preprocess your text before running it through spaCy/spazz using a library like Textacy to strip out accents. This will change the text itself before you run it through spaCy/spaczz. This option probably provides the most flexibility but adds another step. The other option is to use one of RapidFuzz's fuzzy matchers that preprocesses text before fuzzy matching but won't actually change the text itself. You can control this in spaczz at the pattern and/or ruler level just like the examples above.
A word of warning though, the default RapidFuzz preprocessor "remov[es] all non alphanumeric characters - trim[s] whitespaces - convert[s] all characters to lower case" according to it's docs. RapidFuzz supports customizing the preprocessing with a custom callable however, spaczz does not currently support passing a custom callable RapidFuzz. I can add this but it'll probably be later next week before I can get to that.
The following RapidFuzz matchers do preprocessing:
Here's an example of changing the fuzzy matcher on the ruler level:
import spacy
from spaczz.pipeline import SpaczzRuler
nlp = spacy.blank("en")
text = "testing, TESTING"
doc = nlp(text)
patterns = [
{
"label": "TEST",
"pattern": "testing",
"type": "fuzzy",
},
{
"label": "TEST",
"pattern": "TESTING",
"type": "fuzzy",
},
]
ruler = SpaczzRuler(nlp, fuzzy_defaults={"fuzzy_func": "quick"})
ruler.add_patterns(patterns)
doc = ruler(doc)
for ent in doc.ents:
print((ent.text, ent.start, ent.end, ent.label_, ent._.spaczz_ratio))
('testing', 0, 1, 'TEST', 100)
('TESTING', 2, 3, 'TEST', 100)
Hopefully that helps!
Hi @davidggphy did the above adequately answer your question? If you still need/want a feature implemented please let me know and I can track that in this issue, otherwise I will close this issue in the next couple days. Thanks!
Dear @gandersen101 ,
Sorry for my late reply. I tested what you said. Sadly, as you said, RapidFuzz performs preprocessing on the strings, but this does not involve "deaccent". It would be really interesting to add the custom callabale for preprocessing in order to compute the fuzzy scores.
As you said, the other possibility is to preprocess the text before sending it into the matcher, but then the entitities found will be preprocessed accordingly, which is something I would like to prevent. I could hack to later find the same tokens on the original text, but it will be more cumbersome.
Hey @davidggphy, thanks for the additional info. I am planning on doing a spaczz feature upgrade/overhaul in the near future and will keep the ability to add custom preprocessing without modifying the doc in mind. Thanks!
First of all, thanks for the library @gandersen101 . I'm starting using it and it's really powerful.
Using
SpaczzRuler
withfuzzy
patterns, by default it compares strings in a case-insensitive way. Is there a way of changing this behaviour?Similarly, is there a way of comparing strings w/o taking into account accents? This is, making "test" equivalent to "tést". It could be hacked changing the string for a accent-stripped version of it (since it maintains the token structure), but maybe is an easier way.
Output