如何在 Spacy 中添加额外的货币字符
How to add additional currency characters in Spacy
我有文档,其中字符 \u0080
用作欧元。我想将这些字符和其他字符添加到货币符号列表中,以便货币实体被 Spacy NER 拾取。处理此问题的最佳方法是什么?
此外,我还遇到过金钱被表示为 CAD 5,000
的情况,而 NER 并未将其选为金钱。处理这种情况的最佳方法是什么,训练 NER 或添加 CAD
作为货币符号?
1。 'u[=15=]80'
问题
首先,'u[=15=]80'
字符的解释似乎取决于您使用的平台,它不会在 Windows 7 机器上打印,但它可以在 Linux机器...
为了完整起见,我假设您从包含 '€'
转义序列(在浏览器中应打印为 €
)的 html 文档中获取文本,'\u0080'
字符和其他一些我们认为是货币的任意符号。
在将文本内容传递给 spaCy 之前,我们可以调用 html.unescape
,它将负责将 €
翻译成 €
,这将被默认识别配置为货币。
text_html = ("I just found out that CAD 1,000 is about 641.3 €. "
"Some people call it 641.3 \u0080. "
"Fantastic! But in the U.K. I'd rather pay 344 or \U0001F33B56.")
text = html.unescape(text_html)
其次,如果有不被识别为货币的符号,例如</code>和<code>
,那么我们可以改变Defaults
我们用来将它们定义为货币的语言。
这包括用自定义函数替换 lex_attr_getters[IS_CURRENCY]
函数,该函数包含描述货币的符号列表。
def is_currency_custom(text):
# Stripping punctuation
table = str.maketrans({key: None for key in string.punctuation})
text = text.translate(table)
all_currencies = ["\U0001F385", "\U0001F33B", "\u0080", "CAD"]
if text in all_currencies:
return True
return is_currency_original(text)
# Keep a reference to the original is_currency function
is_currency_original = EnglishDefaults.lex_attr_getters[IS_CURRENCY]
# Assign a new function for IS_CURRENCY
EnglishDefaults.lex_attr_getters[IS_CURRENCY] = is_currency_custom
2。 CAD 5,000
问题
对于这个问题,一个简单的解决方案是定义一个特例。我们对分词器说,无论它在哪里遇到 CAD
,这是一个特殊情况,它需要按照我们的指示去做。我们可以设置 IS_CURRENCY
标志等。
special_case = [{
ORTH: u'CAD',
TAG: u'$',
IS_CURRENCY: True}]
nlp.tokenizer.add_special_case(u'CAD', special_case)
请注意,这并不完美,因为您可能会得到误报。想象一下来自一家销售 CAD 绘图服务的加拿大公司的文档...所以这很好但不是很好。
如果我们想要更精确,我们可以创建一个 Matcher
对象,该对象将查找 CURRENCY[SPACE]NUMBER
或 NUMBER[SPACE]CURRENCY
等模式并将 MONEY
实体与它。
matcher = Matcher(nlp.vocab)
MONEY = nlp.vocab.strings['MONEY']
# This is the matcher callback that sets the MONEY entity
def add_money_ent(matcher, doc, i, matches):
match_id, start, end = matches[i]
doc.ents += ((MONEY, start, end),)
matcher.add(
'MoneyRedefined',
add_money_ent,
[{'IS_CURRENCY': True}, {'IS_SPACE': True, 'OP': '?'}, {'LIKE_NUM': True}],
[{'LIKE_NUM': True}, {'IS_SPACE': True, 'OP': '?'}, {'IS_CURRENCY': True}]
)
然后你用 matcher(doc)
将它应用到你的 doc
对象。 'OP'
键使模式可选,允许它匹配 0 或 1 次。
3。完整代码
import spacy
from spacy.symbols import IS_CURRENCY
from spacy.lang.en import EnglishDefaults
from spacy.matcher import Matcher
from spacy import displacy
import html
import string
def is_currency_custom(text):
# Stripping punctuation
table = str.maketrans({key: None for key in string.punctuation})
text = text.translate(table)
all_currencies = ["\U0001F385", "\U0001F33B", "\u0080", "CAD"]
if text in all_currencies:
return True
return is_currency_original(text)
# Keep a reference to the original is_currency function
is_currency_original = EnglishDefaults.lex_attr_getters[IS_CURRENCY]
# Assign a new function for IS_CURRENCY
EnglishDefaults.lex_attr_getters[IS_CURRENCY] = is_currency_custom
nlp = spacy.load('en')
matcher = Matcher(nlp.vocab)
MONEY = nlp.vocab.strings['MONEY']
# This is the matcher callback that sets the MONEY entity
def add_money_ent(matcher, doc, i, matches):
match_id, start, end = matches[i]
doc.ents += ((MONEY, start, end),)
matcher.add(
'MoneyRedefined',
add_money_ent,
[{'IS_CURRENCY': True}, {'IS_SPACE': True, 'OP': '?'}, {'LIKE_NUM': True}],
[{'LIKE_NUM': True}, {'IS_SPACE': True, 'OP': '?'}, {'IS_CURRENCY': True}]
)
text_html = ("I just found out that CAD 1,000 is about 641.3 €. "
"Some people call it 641.3 \u0080. "
"Fantastic! But in the U.K. I'd rather pay 344 or \U0001F33B56.")
text = html.unescape(text_html)
doc = nlp(text)
matcher(doc)
displacy.serve(doc, style='ent')
这给出了预期的:
我有文档,其中字符 \u0080
用作欧元。我想将这些字符和其他字符添加到货币符号列表中,以便货币实体被 Spacy NER 拾取。处理此问题的最佳方法是什么?
此外,我还遇到过金钱被表示为 CAD 5,000
的情况,而 NER 并未将其选为金钱。处理这种情况的最佳方法是什么,训练 NER 或添加 CAD
作为货币符号?
1。 'u[=15=]80'
问题
首先,'u[=15=]80'
字符的解释似乎取决于您使用的平台,它不会在 Windows 7 机器上打印,但它可以在 Linux机器...
为了完整起见,我假设您从包含 '€'
转义序列(在浏览器中应打印为 €
)的 html 文档中获取文本,'\u0080'
字符和其他一些我们认为是货币的任意符号。
在将文本内容传递给 spaCy 之前,我们可以调用 html.unescape
,它将负责将 €
翻译成 €
,这将被默认识别配置为货币。
text_html = ("I just found out that CAD 1,000 is about 641.3 €. "
"Some people call it 641.3 \u0080. "
"Fantastic! But in the U.K. I'd rather pay 344 or \U0001F33B56.")
text = html.unescape(text_html)
其次,如果有不被识别为货币的符号,例如</code>和<code>
,那么我们可以改变Defaults
我们用来将它们定义为货币的语言。
这包括用自定义函数替换 lex_attr_getters[IS_CURRENCY]
函数,该函数包含描述货币的符号列表。
def is_currency_custom(text):
# Stripping punctuation
table = str.maketrans({key: None for key in string.punctuation})
text = text.translate(table)
all_currencies = ["\U0001F385", "\U0001F33B", "\u0080", "CAD"]
if text in all_currencies:
return True
return is_currency_original(text)
# Keep a reference to the original is_currency function
is_currency_original = EnglishDefaults.lex_attr_getters[IS_CURRENCY]
# Assign a new function for IS_CURRENCY
EnglishDefaults.lex_attr_getters[IS_CURRENCY] = is_currency_custom
2。 CAD 5,000
问题
对于这个问题,一个简单的解决方案是定义一个特例。我们对分词器说,无论它在哪里遇到 CAD
,这是一个特殊情况,它需要按照我们的指示去做。我们可以设置 IS_CURRENCY
标志等。
special_case = [{
ORTH: u'CAD',
TAG: u'$',
IS_CURRENCY: True}]
nlp.tokenizer.add_special_case(u'CAD', special_case)
请注意,这并不完美,因为您可能会得到误报。想象一下来自一家销售 CAD 绘图服务的加拿大公司的文档...所以这很好但不是很好。
如果我们想要更精确,我们可以创建一个 Matcher
对象,该对象将查找 CURRENCY[SPACE]NUMBER
或 NUMBER[SPACE]CURRENCY
等模式并将 MONEY
实体与它。
matcher = Matcher(nlp.vocab)
MONEY = nlp.vocab.strings['MONEY']
# This is the matcher callback that sets the MONEY entity
def add_money_ent(matcher, doc, i, matches):
match_id, start, end = matches[i]
doc.ents += ((MONEY, start, end),)
matcher.add(
'MoneyRedefined',
add_money_ent,
[{'IS_CURRENCY': True}, {'IS_SPACE': True, 'OP': '?'}, {'LIKE_NUM': True}],
[{'LIKE_NUM': True}, {'IS_SPACE': True, 'OP': '?'}, {'IS_CURRENCY': True}]
)
然后你用 matcher(doc)
将它应用到你的 doc
对象。 'OP'
键使模式可选,允许它匹配 0 或 1 次。
3。完整代码
import spacy
from spacy.symbols import IS_CURRENCY
from spacy.lang.en import EnglishDefaults
from spacy.matcher import Matcher
from spacy import displacy
import html
import string
def is_currency_custom(text):
# Stripping punctuation
table = str.maketrans({key: None for key in string.punctuation})
text = text.translate(table)
all_currencies = ["\U0001F385", "\U0001F33B", "\u0080", "CAD"]
if text in all_currencies:
return True
return is_currency_original(text)
# Keep a reference to the original is_currency function
is_currency_original = EnglishDefaults.lex_attr_getters[IS_CURRENCY]
# Assign a new function for IS_CURRENCY
EnglishDefaults.lex_attr_getters[IS_CURRENCY] = is_currency_custom
nlp = spacy.load('en')
matcher = Matcher(nlp.vocab)
MONEY = nlp.vocab.strings['MONEY']
# This is the matcher callback that sets the MONEY entity
def add_money_ent(matcher, doc, i, matches):
match_id, start, end = matches[i]
doc.ents += ((MONEY, start, end),)
matcher.add(
'MoneyRedefined',
add_money_ent,
[{'IS_CURRENCY': True}, {'IS_SPACE': True, 'OP': '?'}, {'LIKE_NUM': True}],
[{'LIKE_NUM': True}, {'IS_SPACE': True, 'OP': '?'}, {'IS_CURRENCY': True}]
)
text_html = ("I just found out that CAD 1,000 is about 641.3 €. "
"Some people call it 641.3 \u0080. "
"Fantastic! But in the U.K. I'd rather pay 344 or \U0001F33B56.")
text = html.unescape(text_html)
doc = nlp(text)
matcher(doc)
displacy.serve(doc, style='ent')
这给出了预期的: