【问题标题】:Distinguishing well formed English sentences from "word salad"区分格式良好的英语句子和“单词沙拉”
【发布时间】:2015-10-11 17:16:45
【问题描述】:

我正在寻找一个易于使用 C++、Python 或 F# 的库,它可以区分格式良好的英语句子和“单词沙拉”。我试过The Stanford Parser,不幸的是,它解析了这个:

Some plants have with done stems animals with exercise that to predict?

毫无怨言。我不是在寻找非常复杂的东西,能够处理所有可能的极端情况。我只需要过滤掉一个明显的废话。

【问题讨论】:

  • 看看这个问题的第二个答案。 stackoverflow.com/questions/10252448/… 让图书馆检查句子的语法和拼写错误,而不仅仅是尝试找到最可能的解析,应该是要走的路。
  • @HugoMailhot 好建议,但不会一帆风顺。我将我的测试语句提供给LanguageTool,它顺利通过了。

标签: nlp stanford-nlp


【解决方案1】:

这是我刚刚偶然发现的: A general-purpose sentence-level nonsense detector,由斯坦福大学学生 Ian Tenney 撰写。

Here is the code from the project, undocumented but available on GitHub.

如果你想在此基础上开发自己的解决方案,我认为你应该注意第 3 节“特征和预处理”下使用的第 4 组特征,即语言模型。

这可能还不够,但我认为获得每个长度为 n 的子序列的概率分数是一个好的开始。像“plants have with”、“have with done”、“done stems animals”、“stems animals with”和“that to predict”这样的 3-gram 似乎不太可能,这可能导致整个句子上出现“废话”标签.

这种方法的优点是依赖于学习模型,而不是一组手工制定的规则,afaik 是您的另一个选择。很多人会把你指向Chapter 8 of NLTK's manual,但我认为为通用英语开发自己的上下文无关语法要求有点高。

【讨论】:

  • 代码链接已弃用
【解决方案2】:

这篇论文很有用,但是对于解决这个问题来说太深入了。这里是作者的basic approach,启发式:

  1. 基线句子启发式:首字母大写, 并且行以 .?! 之一结束(1 feature)。
  2. 字符、单词、标点符号、数字和命名实体的数量(来自 Stanford CoreNLP NER 标记器),以及按文本长度的标准化版本 (10 features)。
  3. 词性分布标签:(# / # words) 用于每个 Penn 树库标签 (45 features)。
  4. 第一个词性标签的指示符 以及文本中的最后一个标记 (45x2 = 90 features)。
  5. 语言模型原始分数(s lm = log p(text)) 和归一化分数 (s¯lm = s lm / # words) (2 features)。

然而,经过大量搜索,github repo 只包含测试和可视化。原始训练和测试数据不存在。这是他计算这些特征的函数:

(注意:这里使用 pandas 数据帧作为 df)

def make_basic_features(df):
    """Compute basic features."""

    df['f_nchars'] = df['__TEXT__'].map(len)
    df['f_nwords'] = df['word'].map(len)

    punct_counter = lambda s: sum(1 for c in s
                                  if (not c.isalnum())
                                      and not c in
                                        [" ", "\t"])
    df['f_npunct'] = df['__TEXT__'].map(punct_counter)
    df['f_rpunct'] = df['f_npunct'] / df['f_nchars']

    df['f_ndigit'] = df['__TEXT__'].map(lambda s: sum(1 for c in s
                                  if c.isdigit()))
    df['f_rdigit'] = df['f_ndigit'] / df['f_nchars']

    upper_counter = lambda s: sum(1 for c in s if c.isupper())
    df['f_nupper'] = df['__TEXT__'].map(upper_counter)
    df['f_rupper'] = df['f_nupper'] / df['f_nchars']

    df['f_nner'] = df['ner'].map(lambda ts: sum(1 for t in ts
                                              if t != 'O'))
    df['f_rner'] = df['f_nner'] / df['f_nwords']

    # Check standard sentence pattern:
    # if starts with capital, ends with .?!
    def check_sentence_pattern(s):
        ss = s.strip(r"""`"'""").strip()
        return s[0].isupper() and (s[-1] in '.?!')
    df['f_sentence_pattern'] = df['__TEXT__'].map(check_sentence_pattern)

    # Normalize any LM features
    # by dividing logscore by number of words
    lm_cols = {c:re.sub("_lmscore_", "_lmscore_norm_",c)
               for c in df.columns if c.startswith("f_lmscore")}
    for c,cnew in lm_cols.items():
        df[cnew] = df[c] / df['f_nwords']

    return df

所以我想这是您可以在这种情况下使用的功能。极简版:

raw = ["This is is a well-formed sentence","but this ain't a good sent","just a fragment"]
import pandas as pd
df = pd.DataFrame([{"__TEXT__":i, "word": i.split(), 'ner':[]} for i in raw])

解析器似乎想要一个单词列表,以及使用 Java 编写的 Stanford CoreNLP 库识别的命名实体 (NER)。您可以不传入任何内容(一个空列表[]),并且该函数会计算其他所有内容。您将获得一个包含句子所有特征的数据框(如矩阵),然后您可以根据给定的规则使用这些特征来决定什么叫做“格式良好”。

此外,您不必在这里使用 pandas。字典列表也可以使用。但是原始代码使用了 pandas。

因为这个例子涉及很多步骤,所以我创建了一个要点,我在其中运行了一个例子,直到产生一个干净的句子列表和一个脏列表的格式不正确的句子

我的要点: https://gist.github.com/marcmaxson/4ccca7bacc72eb6bb6479caf4081cefb

这用spacy 替换了Stanford CoreNLP java 库 - 一个更新且更易于使用的 python 库,用于填充缺失的元数据,例如情绪、命名实体和用于确定句子是否正确的词性格式良好。这在 python 3.6 下运行,但可以在 2.7 下运行。所有库都向后兼容。

【讨论】:

  • 随着我的改进,接下来我将在句子结构中寻找主谓,句子不以形容词结尾......类似的东西。
猜你喜欢
  • 2016-07-18
  • 2020-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多