我正在复制本文中描述的算法:https://arxiv.org/pdf/1811.11008.pdf
在最后一页,它使用以下示例描述了提取语法中定义的'NP JJ‘中定义的叶子:营业利润率为8.3%,而去年同期为11.8%。
我期望看到一片标有'NP JJ‘的叶子,但我没有看到。我正在绞尽脑汁地解释为什么(正则表达式相对较新)。
def split_sentence(sentence_as_string):
''' function to split sentence into list of words
'''
words = word_tokenize(sentence_as_string)
return words
def pos_tagging(sentence_as_list):
words = nltk.pos_tag(sentence_as_list)
return words
def get_regex(sentence, grammar):
sentence = pos_tagging(split_sentence(sentence));
cp = nltk.RegexpParser(grammar)
result = cp.parse(sentence)
return result
example_sentence = "Operating profit margin was 8.3%, compared to 11.8% a year earlier."
grammar = """JJ : {< JJ.∗ > ∗}
V B : {< V B.∗ >}
NP : {(< NNS|NN >)∗}
NP P : {< NNP|NNP S >}
RB : {< RB.∗ >}
CD : {< CD >}
NP JJ : : {< NP|NP P > +(< (>< .∗ > ∗ <) >) ∗ (< IN >< DT > ∗ < RB > ∗ < JJ > ∗ < NP|NP P >) ∗ < RB > ∗(< V B >< JJ >< NP >)∗ < V B > (< DT >< CD >< NP >) ∗ < NP|NP P > ∗ < CD > ∗ < .∗ > ∗ < CD > ∗| < NP|NP P >< IN >< NP|NP P >< CD >< .∗ > ∗ <, >< V B > < IN >< NP|NP P >< CD >}"""
grammar = grammar.replace('∗','*')
tree = get_regex(example_sentence, grammar)
print(tree)发布于 2020-05-13 08:29:45
首先,请参阅How to use nltk regex pattern to extract a specific phrase chunk?
让我们看看句子的词性标签是什么:
from nltk import word_tokenize, pos_tag
text = "Operating profit margin was 8.3%, compared to 11.8% a year earlier."
pos_tag(word_tokenize(text))输出
[('Operating', 'NN'),
('profit', 'NN'),
('margin', 'NN'),
('was', 'VBD'),
('8.3', 'CD'),
('%', 'NN'),
(',', ','),
('compared', 'VBN'),
('to', 'TO'),
('11.8', 'CD'),
('%', 'NN'),
('a', 'DT'),
('year', 'NN'),
('earlier', 'RBR'),
('.', '.')]首先抓到你了!任何标记中都没有JJ
这句话中的任何一个词性都没有JJ标签。
让我们回到纸质的https://arxiv.org/pdf/1811.11008.pdf

尽管如此,NP JJ并不是最终目标;最终目标是基于一些启发式方法生成UP或DOWN标签。
让我们重新表述这些步骤:
2a。遍历解析树以提取另一个模式,它告诉我们有关性能指示器和数值的信息。
2b。使用提取的提取的数值来确定方向性UP / DOWN,使用一些启发式
2c。用(2b)中标识的UP / Down标记句子
让我们看看我们可以先构建哪个组件。
2b。提取另一个模式,它告诉我们有关性能指标和数值的信息。
我们知道某个百分比的输出总是CD NN from
('8.3', 'CD'), ('%', 'NN')
('11.8', 'CD'), ('%', 'NN')因此,让我们尝试在语法中捕捉到这一点。
patterns = """
PERCENT: {<CD><NN>}
"""
PChunker = RegexpParser(patterns)
PChunker.parse(pos_tag(word_tokenize(text)))输出
Tree('S', [('Operating', 'NN'), ('profit', 'NN'), ('margin', 'NN'), ('was', 'VBD'),
Tree('PERCENT', [('8.3', 'CD'), ('%', 'NN')]),
(',', ','), ('compared', 'VBN'), ('to', 'TO'),
Tree('PERCENT', [('11.8', 'CD'), ('%', 'NN')]),
('a', 'DT'), ('year', 'NN'), ('earlier', 'RBR'), ('.', '.')])现在,我们如何得到这个:
我们知道<PERCENT> compared to <PERCENT>是一个很好的模式,所以让我们尝试对它进行编码。
我们知道compared to有来自VBN TO的标签
('8.3', 'CD'),
('%', 'NN'),
(',', ','),
('compared', 'VBN'),
('to', 'TO'),
('11.8', 'CD'),
('%', 'NN'),这样如何:
patterns = """
PERCENT: {<CD><NN>}
P2P: {<PERCENT><.*>?<VB.*><TO><PERCENT>}
"""
PChunker = RegexpParser(patterns)
PChunker.parse(pos_tag(word_tokenize(text)))输出
Tree('S', [('Operating', 'NN'), ('profit', 'NN'), ('margin', 'NN'), ('was', 'VBD'),
Tree('P2P', [
Tree('PERCENT', [('8.3', 'CD'), ('%', 'NN')]),
(',', ','), ('compared', 'VBN'), ('to', 'TO'),
Tree('PERCENT', [('11.8', 'CD'), ('%', 'NN')])]
),
('a', 'DT'), ('year', 'NN'), ('earlier', 'RBR'), ('.', '.')]
)但是这个模式可以是任意的数字。我们需要performance indicator的信号
由于我不是金融领域的领域专家,简单地使用operating profit margin的存在可能是一个好的信号,例如
from nltk import word_tokenize, pos_tag, RegexpParser
patterns = """
PERCENT: {<CD><NN>}
P2P: {<PERCENT><.*>?<VB.*><TO><PERCENT>}
"""
PChunker = RegexpParser(patterns)
text = "Operating profit margin was 8.3%, compared to 11.8% a year earlier."
indicators = ['operating profit margin']
for i in indicators:
if i in text.lower():
print(PChunker.parse(pos_tag(word_tokenize(text))))输出
(S
Operating/NN
profit/NN
margin/NN
was/VBD
(P2P
(PERCENT 8.3/CD %/NN)
,/,
compared/VBN
to/TO
(PERCENT 11.8/CD %/NN))
a/DT
year/NN
earlier/RBR
./.)现在,我们如何获取UP / DOWN
2b。使用提取的数值通过一些启发式方法来确定向上/向下的方向
仅从示例句子中,除了“较早”之外,没有任何其他信息告诉我们数字的先行关系。
所以让我们假设一下,如果我们有模式PERCENT VBN TO PERCENT earlier,我们说2%是一个更老的数字。
import nltk
from nltk import word_tokenize, pos_tag, RegexpParser
patterns = """
PERCENT: {<CD><NN>}
P2P: {<PERCENT><.*>?<VB.*><TO><PERCENT><.*>*<RBR>}
"""
def traverse_tree(tree, label=None):
# print("tree:", tree)
for subtree in tree:
if type(subtree) == nltk.tree.Tree and subtree.label() == label:
yield subtree
PChunker = RegexpParser(patterns)
parsed_text = PChunker.parse(pos_tag(word_tokenize(text)))
for p2p in traverse_tree(parsed_text, 'P2P'):
print(p2p)输出
(P2P
(PERCENT 8.3/CD %/NN)
,/,
compared/VBN
to/TO
(PERCENT 11.8/CD %/NN)
a/DT
year/NN
earlier/RBR)那么UP / DOWN标签呢?
import nltk
from nltk import word_tokenize, pos_tag, RegexpParser
patterns = """
PERCENT: {<CD><NN>}
P2P: {<PERCENT><.*>?<VB.*><TO><PERCENT><.*>*<RBR>}
"""
PChunker = RegexpParser(patterns)
def traverse_tree(tree, label=None):
# print("tree:", tree)
for subtree in tree:
if type(subtree) == nltk.tree.Tree and subtree.label() == label:
yield subtree
def labelme(text):
parsed_text = PChunker.parse(pos_tag(word_tokenize(text)))
for p2p in traverse_tree(parsed_text, 'P2P'):
# Check if the subtree ends with "earlier".
if p2p.leaves()[-1] == ('earlier', 'RBR'):
# Check if which percentage is larger.
percentages = [float(num[0]) for num in p2p.leaves() if num[1] == 'CD']
# Sanity check that there's only 2 numbers from our pattern.
assert len(percentages) == 2
if percentages[0] > percentages[1]:
return 'DOWN'
else:
return 'UP'
text = "Operating profit margin was 8.3%, compared to 11.8% a year earlier."
labelme(text)现在问题来了.
**您是否想编写这么多规则,并使用上面的labelme()来捕获它们?**
你写的模式是不是万无一失?
例如,会不会出现这样的情况:使用指示器比较百分比的模式和“较早”不会像预期的那样“向上”或“向下”
为什么我们要在AI时代编写规则?
你是否已经有了带有句子和相应的向上/向下标签的人工注释数据?如果有,让我推荐https://allennlp.org/tutorials或https://github.com/huggingface/transformers/blob/master/notebooks/03-pipelines.ipynb之类的东西
https://stackoverflow.com/questions/61756189
复制相似问题