首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用NLTK正则表达式模式来标注带有UP/DOWN指标的财经新闻?

如何使用NLTK正则表达式模式来标注带有UP/DOWN指标的财经新闻?
EN

Stack Overflow用户
提问于 2020-05-12 23:56:23
回答 1查看 149关注 0票数 4

我正在复制本文中描述的算法:https://arxiv.org/pdf/1811.11008.pdf

在最后一页,它使用以下示例描述了提取语法中定义的'NP JJ‘中定义的叶子:营业利润率为8.3%,而去年同期为11.8%。

我期望看到一片标有'NP JJ‘的叶子,但我没有看到。我正在绞尽脑汁地解释为什么(正则表达式相对较新)。

代码语言:javascript
复制
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)
EN

回答 1

Stack Overflow用户

发布于 2020-05-13 08:29:45

首先,请参阅How to use nltk regex pattern to extract a specific phrase chunk?

让我们看看句子的词性标签是什么:

代码语言:javascript
复制
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))

输出

代码语言:javascript
复制
[('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并不是最终目标;最终目标是基于一些启发式方法生成UPDOWN标签。

让我们重新表述这些步骤:

  1. 使用解析器(在本例中,使用某种形式的正则表达式解析器)解析句子,表示句子具有模式,它可以告诉用户关于最终标签的用法。

2a。遍历解析树以提取另一个模式,它告诉我们有关性能指示器和数值的信息。

2b。使用提取的提取的数值来确定方向性UP / DOWN,使用一些启发式

2c。用(2b)中标识的UP / Down标记句子

让我们看看我们可以先构建哪个组件。

2b。提取另一个模式,它告诉我们有关性能指标和数值的信息。

我们知道某个百分比的输出总是CD NN from

代码语言:javascript
复制
('8.3', 'CD'), ('%', 'NN')
('11.8', 'CD'), ('%', 'NN')

因此,让我们尝试在语法中捕捉到这一点。

代码语言:javascript
复制
patterns = """
PERCENT: {<CD><NN>}
"""

PChunker = RegexpParser(patterns)
PChunker.parse(pos_tag(word_tokenize(text)))

输出

代码语言:javascript
复制
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'), ('.', '.')])

现在,我们如何得到这个:

  1. Identify表示句子有一个模式,可以告诉用户关于最终标签的用法。

我们知道<PERCENT> compared to <PERCENT>是一个很好的模式,所以让我们尝试对它进行编码。

我们知道compared to有来自VBN TO的标签

代码语言:javascript
复制
 ('8.3', 'CD'),
 ('%', 'NN'),
 (',', ','),
 ('compared', 'VBN'),
 ('to', 'TO'),
 ('11.8', 'CD'),
 ('%', 'NN'),

这样如何:

代码语言:javascript
复制
patterns = """
PERCENT: {<CD><NN>}
P2P: {<PERCENT><.*>?<VB.*><TO><PERCENT>}
"""

PChunker = RegexpParser(patterns)
PChunker.parse(pos_tag(word_tokenize(text)))

输出

代码语言:javascript
复制
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的存在可能是一个好的信号,例如

代码语言:javascript
复制
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))))

输出

代码语言:javascript
复制
(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%是一个更老的数字。

代码语言:javascript
复制
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)

输出

代码语言:javascript
复制
(P2P
  (PERCENT 8.3/CD %/NN)
  ,/,
  compared/VBN
  to/TO
  (PERCENT 11.8/CD %/NN)
  a/DT
  year/NN
  earlier/RBR)

那么UP / DOWN标签呢?

代码语言:javascript
复制
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/tutorialshttps://github.com/huggingface/transformers/blob/master/notebooks/03-pipelines.ipynb之类的东西

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61756189

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档