首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不一致地划分句子

不一致地划分句子
EN

Stack Overflow用户
提问于 2021-08-23 08:00:44
回答 3查看 659关注 0票数 2

我正在使用Spacy,我对它如何分割句子有问题。由于某些原因,一些句子被分割成两个或多个部分,而不是一个,所以当我尝试用TensorFlow训练一个模型时,我得到了一个向量维数不匹配的错误。

我已经尝试将令牌更改为空白标记,如此链接中所示。因此,我的类看起来像( Benepar组件注释掉了):

代码语言:javascript
复制
class BeneparAnnotator(SyntaxAnnotator):
    class WhitespaceTokenizer:
        def __init__(self, vocab):
            self.vocab = vocab

        def __call__(self, text):
            words = text.split(" ")
            spaces = [True] * len(words)
            # Avoid zero-length tokens
            for i, word in enumerate(words):
                if word == "":
                    words[i] = " "
                    spaces[i] = False
            # Remove the final trailing space
            if words[-1] == " ":
                words = words[0:-1]
                spaces = spaces[0:-1]
            else:
                spaces[-1] = False

            return Doc(self.vocab, words=words, spaces=spaces)

    def __init__(self):
        self.nlp = spacy.load('en')
        # self.nlp.add_pipe(BeneparComponent("benepar_en2"))
        self.nlp.tokenizer = self.WhitespaceTokenizer(self.nlp.vocab)
        self.extract_arc_representation = False
   
    ... other stuff ...


def ... other stuff ...

现在,当用以下方法分析句子时:

代码语言:javascript
复制
def parse_sentences(nlp, captions: List[str]) -> List[Span]:

    parsed_sentences = []
    for caption in tqdm(captions, desc="Parsing sentences"):
        parsed_caption = nlp(caption)
        if len(list(parsed_caption.sents)) > 1:  # This if is for debug
            length = len(list(parsed_caption.sents))
            as_list = list(parsed_caption.sents)
            pass
        parsed_sentence = list(parsed_caption.sents)[0]
        parsed_sentences.append(parsed_sentence)

    return parsed_sentences

这种获得句子的方法取自这里,因为我想检索与Benepar解析的句子,但是其中一些句子被分成几个句子,而不是得到全部解析的句子,我得到了几个被解析的句子。

出于某种原因,对于某些句子,它们被分成2或3部分:

  • 一只刚刚剃掉头发的害群之马 它分成两部分:一只害群之马,刚刚剃掉了它的毛。
  • 例2:路标上写着s.3av。不向左转 分为:街牌上写着s.,3 av.,没有左转。
  • 例3:一个拐弯处的路只在路中间标出。 它被划分为:一个转弯的路,只有在路中间的标志
  • 例4:两头牛站在树前的草地上。 它分成两只:两头母牛站在树前的草地上
  • 例5:一辆德比车# 30被看到在右车门半开的情况下切角。 它被分成两部分:一辆德比车,# 30是用右车门半开着切割一个角落的。

我还有其他类似于例1的句子,它们被正确地分割成一个句子。例如:

一只站在草地上的背羊

它被分成两部分:一只站在草地上的后羊

因此,当我用list(parsed_caption.sents)[0]得到一个标题时,我得到的是整个标题,而不是标题的一部分。

问题出在哪里?

-更新一下,想更好地解释我的问题

我有一个句子清单,我想用Benepar来分析,然后用它们作为工具的输入,看看我是否得到了更好的结果。由于该工具的anaconda环境的限制,我需要使用2019年版本,它是在Python3.6上工作的版本。

我遇到的问题是,一些句子被拆分,Benepar将它们解析为独立的块(而不是整个句子),当我试图用list(parsed_caption.sents)[0] (因为应该只有一个元素,整个句子)来获取它们时,我只得到了一个块,当我运行实验时,我得到了一个错误,即原始句子和解析的句子的大小不匹配。

我对这套训练有超过616 K的句子。它们中的大多数都被分析得很好,不被分割成块,如果我这样做的话:

代码语言:javascript
复制
caption = list(parsed_caption.sents)[0]

然后:

代码语言:javascript
复制
caption._.parse_string

我从Benepar那里得到了所有分析过的句子。

假设我有一句话:The time for action is now.

我在list(parsed_caption.sents)[0]中的预期内容应该是:

代码语言:javascript
复制
[The time for action is now.]

因此,当我想得到caption._.parse_string解析的句子时,我得到:

代码语言:javascript
复制
(S (NP (NP (DT The) (NN time)) (PP (IN for) (NP (NN action)))) (VP (VBZ is) (ADVP (RB now))) (. .))

但问题是,对于某些句子,它们被划分为(例如):

代码语言:javascript
复制
[The time, for action is now.]

所以,如果我尝试用list(parsed_caption.sents)[0]来得到这个句子,我只会得到一大块的解析。我只期待一句话,不会再多了。

由于只有时间,当我训练模型和句子的时候,行动的时间到了。如果选中,我将得到一个错误,因为操作时间的长度是现在。时间也不一样。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-08-24 09:18:09

我终于找到了解决我的需要的办法。

由于tool 伯克利神经分析器提供了两个选项(NLTK和Spacy),所以我尝试了NLTK选项并设法实现了我的目标。由于环境的限制,我不得不使用支持Python3.6的2019年版本。

对于NLTK,我只需要做:

代码语言:javascript
复制
import benepar

class BeneparAnnotator(SyntaxAnnotator):
    def __init__(self):
        self.parser = benepar.Parser("benepar_en2")
        self.extract_arc_representation = False
....

然后:

代码语言:javascript
复制
for caption in tqdm(captions, desc="Parsing sentences"):
    parsed_caption = parser.parse(caption)
    tree_as_string = parsed_caption.pformat(margin=500, indent=0, nodesep='', parens='()', quotes=False)
    parsed_sentences.append(tree_as_string)

tree_as_string中,您将得到解析的句子:

代码语言:javascript
复制
(S (NP (DT a) (NN restaurant)) (VP (VBZ has) (NP (JJ modern) (JJ wooden) (NNS tables) (CC and) (NNS chairs)))) 

您必须调整margin参数以设置短语的长度,因为如果短语长度大于页边距,则pformat将以这种方式将其分割为几行带有\n字符的行(确切地说,只是显示一个示例):

代码语言:javascript
复制
(S\n (NP\n (DT a)\n (NN restaurant)) (VP\n (VBZ has) (NP\n (JJ modern) (JJ wooden) (NNS tables) (CC and) (NNS chairs)))) 

在这种情况下,所有的句子都被正确地处理了,我可以训练模型,而不需要区分最初的标号向量和解析的向量的长度,因为现在有Spacy的句子被分割成几个部分,不再被分成几个部分。

我希望这能帮助使用相同版本的工具的人。

诚挚的问候。

票数 0
EN

Stack Overflow用户

发布于 2021-08-23 08:52:24

我不会在您的阶段使用定制标记器,并且肯定不会分割空格,请使用spacy常规标记器:

代码语言:javascript
复制
        from spacy.tokenizer import Tokenizer 

        self.nlp = spacy.load("en")     
        self.nlp.tokenizer=Tokenizer(self.nlp.vocab)  

如果您想看到令牌:

代码语言:javascript
复制
def _TokoniezData(self,sentence):
        self.doc = self.nlp(sentence)
        self._tokonized=[]
        for token in self.doc:           
             self._tokonized.append((token.text ,token.lemma_, token.pos_, token.tag_, token.dep_,
                    token.shape_, token.is_alpha, token.is_stop,token.head,token.left_edge,token.right_edge,token.ent_type_))
票数 0
EN

Stack Overflow用户

发布于 2021-08-23 10:50:26

我对你想做的事情很困惑,但我的理解是:

  1. 您有一个纯文本文档列表。你知道每一句都是一句话。
  2. 你以某种方式将这个句子传递给贝内帕来得到解析。
  3. 您还希望将spaCy令牌传递给Tensorflow。(我不明白怎么/为什么,但没问题。)

您的问题是,benepar可靠地返回一句话,但spaCy不返回,这会导致Tensorflow的维度问题。

如果上面有任何错误,请纠正我。

假设这是正确的,则令牌程序与您的问题无关。它决定了字符串是如何分裂成单词的,而不是句子是如何定义的。(拥有不同数量的令牌也可能导致维度问题,但听起来这并不是您的问题。)

如果您只想要一个来自spaCy的文本标记列表,您可以这样做:

代码语言:javascript
复制
tokens = list(nlp(text))

就这样。如果您已经知道每个输入应该是一个句子,则不需要使用句子迭代器。

我还注意到,您链接到的指令来自于旧版本的docs,并不真正适用于最新版本的benepar。使用最新版本和当前的自述,我能够编写下面的示例代码,将输入的文本分割成一个句子,没有问题。(我确实收到了火炬发出的警告,但这似乎是内部的一些事情。)

代码语言:javascript
复制
import benepar, spacy
nlp = spacy.load('en_core_web_md')
nlp.add_pipe("benepar", config={"model": "benepar_en3"})
doc = nlp("a black sheep having just had it s haired shaved off")

for sent in doc.sents:
    print(sent)
    print(sent._.parse_string)
    print("---")
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68889124

复制
相关文章

相似问题

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