Как вы разбираете абзац текста в предложения? (желательно в рубине) - PullRequest
22 голосов
/ 14 мая 2009

Как вы берете абзац или большой объем текста и разбиваете его на предложения (желательно с использованием Ruby) с учетом таких случаев, как Mr. and Dr. и U.S.A? (Предполагая, что вы просто помещаете предложения в массив массивов)

UPDATE: Одно возможное решение, о котором я подумал, заключается в использовании тега частей речи (POST) и классификатора для определения конца предложения:

Получив данные от мистера Джонса, он почувствовал теплое солнце на его лице, когда он вышел на балкон своего летнего дома в Италии. Он был счастлив быть живым.

КЛАССИФИКАТОРЫ Г-н / ЧЕЛОВЕК Джонс / ЧЕЛОВЕК чувствовал / O / O тепло / O солнце / O on / O его / O лицо / O как / O он / O вышел / O / O на / O / O балкон / O из / O его / O лето / O дома / O в / O Италия / LOCATION ./O Он / O был / O счастлив / O to / O быть / O жив / O ./O

POST Г-н / NNP Джонс / NNP чувствовал / VBD / DT тепло / JJ солнце / NN / IN / его PRP $ лицо / NN как / IN он / PRP вышел / VBD / RP на / IN / балкон DT / NN / IN его / PRP $ лето / NN home / NN in / IN Италия ./NNP Он / PRP был / VBD счастлив / JJ to / TO be / VB жив. / IN

Можем ли мы предположить, что, поскольку Италия является местом, период является действительным концом предложения? С окончанием на "мистер" не было бы других частей речи, можем ли мы предположить, что это недопустимый период окончания предложения? Это лучший ответ на мой вопрос?

Мысли

Ответы [ 15 ]

13 голосов
/ 14 мая 2009

Попробуйте взглянуть на Ruby-оболочку вокруг Stanford Parser . Имеет функцию getSentencesFromString ().

8 голосов
/ 14 мая 2009

Просто чтобы прояснить, простого решения для этого не существует. Это тема исследования НЛП, как показывает быстрый поиск в Google .

Однако, похоже, что есть несколько проектов с открытым исходным кодом, связанных с NLP, поддерживающими обнаружение предложений, я обнаружил следующий набор инструментов на основе Java:

OpenNLP

Дополнительный комментарий: Проблема определения, где начинаются и заканчиваются предложения, также называется устранение неоднозначности границ предложения (SBD) в обработка естественного языка .

5 голосов
/ 06 мая 2010

Похоже, этот рубиновый камень может помочь.

https://github.com/zencephalon/Tactful_Tokenizer

5 голосов
/ 26 мая 2009

Взгляните на разделитель предложений Python в NLTK (Набор инструментов для естественного языка):

токенайзер предложения Punkt

Он основан на следующей статье:

Kiss, Tibor and Strunk, Jan (2006): Обнаружение границы многоязычного предложения без присмотра . Компьютерная лингвистика 32: 485-525.

Подход в статье довольно интересный. Они сводят проблему разделения предложения к проблеме определения того, насколько сильно слово связано с последующей пунктуацией. Перегрузка периодов после сокращений ответственна за большинство неоднозначных периодов, поэтому, если вы можете определить сокращения, вы можете определить границы предложений с высокой вероятностью.

Я немного неформально протестировал этот инструмент, и, похоже, он дает хорошие результаты для различных (человеческих) языков.

Портировать его на Ruby было бы нетривиально, но это может дать вам некоторые идеи.

4 голосов
/ 14 мая 2009

Это сложная проблема, если вы действительно хотите правильно ее понять. Вы обнаружите, что пакеты анализатора NLP, вероятно, предоставляют эту функциональность. Если вы хотите что-то более быстрое, вам придется в конечном итоге дублировать некоторые из этих функций с помощью обученной вероятностной функции окна токенов (вы, вероятно, захотите считать перевод строки как токен, поскольку я могу отбросить точку, если это конец абзаца).

Редактировать: я рекомендую синтаксический анализатор Стэнфорда, если вы можете использовать Java. У меня нет рекомендаций по другим языкам, но мне очень интересно услышать, что еще есть с открытым исходным кодом.

2 голосов
/ 14 мая 2009

К сожалению, я не рубиновый парень, но, возможно, пример на Perl поможет вам двигаться в правильном направлении. Используя несоответствие, ищите конечную пунктуацию в конце, затем в некоторых особых случаях в не позади следует любой пробел, за которым следует заглавная буква. Я уверен, что это не идеально, но я надеюсь, что это направит вас в правильном направлении. Не знаю, как вы узнали бы, действительно ли США в конце предложения ...

#!/usr/bin/perl

$string = "Mr. Thompson is from the U.S.A. and is 75 years old. Dr. Bob is a dentist. This is a string that contains several sentances. For example this is one. Followed by another. Can it deal with a question?  It sure can!";

my @sentances = split(/(?:(?<=\.|\!|\?)(?<!Mr\.|Dr\.)(?<!U\.S\.A\.)\s+(?=[A-Z]))/, $string);

for (@sentances) {
    print $_."\n";
}
1 голос
/ 27 декабря 2016

Согласитесь с принятым ответом, использование Stanford Core NLP не составляет труда.

Однако в 2016 году существуют некоторые несовместимости , связывающие Stanford Parser с более поздними версиями stanford core nlp (у меня были проблемы с Stanford Core NLP v3.5 ).

Вот что я сделал, чтобы разбить текст на предложения, используя Ruby-интерфейс со Stanford Core NLP :

  1. Установите Stanford CoreNLP gem - он все еще поддерживается и работает, он пытался найти рубиновые камни NLP, которые работают в последнее время:

    gem install stanford-core-nlp

  2. Затем следуйте инструкциям в файле для использования последней версии Stanford CoreNLP :

Использование последней версии Stanford CoreNLP (версия 3.5.0 от 31/10/2014) требуется выполнить несколько дополнительных шагов:

  • Загрузить Stanford CoreNLP версии 3.5.0 с http://nlp.stanford.edu/.

  • Поместите содержимое извлеченного архива в папку / bin / камень stanford-core-nlp (например, [...] / gems / stanford-core-nlp-0.x / bin /) или внутри каталога, настроенного настройкой StanfordCoreNLP.jar_path.

  • Загрузите полную версию Stanford Tagger 3.5.0 с http://nlp.stanford.edu/.
  • Создайте каталог с именем 'taggers' в папке / bin / гема stanford-core-nlp (например, [...] / gems / stanford-core-nlp-0.x / bin /) или внутри каталога настраивается путем настройки StanfordCoreNLP.jar_path.
  • Поместите содержимое извлеченный архив в каталоге taggers.
  • Загрузка файла bridge.jar из https://github.com/louismullie/stanford-core-nlp.
  • Поместите загруженный файл bridger.jar в папку / bin / камень stanford-core-nlp (например, [...] / gems / stanford-core-nlp-0.x / bin / taggers /) или внутри каталога настраивается путем установки StanfordCoreNLP.jar_path.

Затем код рубина для разбиения текста на предложения:

require "stanford-core-nlp"

#I downloaded the StanfordCoreNLP to a custom path:
StanfordCoreNLP.jar_path = "/home/josh/stanford-corenlp-full-2014-10-31/"

StanfordCoreNLP.use :english
StanfordCoreNLP.model_files = {}
StanfordCoreNLP.default_jars = [
  'joda-time.jar',
  'xom.jar',
  'stanford-corenlp-3.5.0.jar',
  'stanford-corenlp-3.5.0-models.jar',
  'jollyday.jar',
  'bridge.jar'
]

pipeline =  StanfordCoreNLP.load(:tokenize, :ssplit)

text = 'Mr. Josh Weir is writing some code. ' + 
  'I am Josh Weir Sr. my son may be Josh Weir Jr. etc. etc.'
text = StanfordCoreNLP::Annotation.new(text)
pipeline.annotate(text)
text.get(:sentences).each{|s| puts "sentence: " + s.to_s}

#output:
#sentence: Mr. Josh Weir is writing some code.
#sentence: I am Josh Weir Sr. my son may be Josh Weir Jr. etc. etc.
1 голос
/ 13 февраля 2013

Я не пробовал, но если английский является единственным языком, который вас интересует, я бы предложил взглянуть на Lingua :: EN :: Читаемость .

Lingua :: EN :: Readability - это модуль Ruby, который вычисляет статистику по тексту на английском языке. Он может предоставить количество слов, предложений и слогов. Он также может рассчитать несколько показателей читабельности, таких как индекс тумана и уровень Флеша-Кинкейда. Пакет включает в себя модуль Lingua :: EN :: Sentence, который разбивает английский текст на предложения, учитывающие сокращения, и Lingua :: EN :: Syllable, который может угадать количество слогов в письменном английском слове. Если доступен словарь произношения, он может найти количество слогов в словаре для большей точности

Требуемый бит находится в sentence.rb следующим образом:

module Lingua
module EN
# The module Lingua::EN::Sentence takes English text, and attempts to split it
# up into sentences, respecting abbreviations.

module Sentence
  EOS = "\001" # temporary end of sentence marker

  Titles   = [ 'jr', 'mr', 'mrs', 'ms', 'dr', 'prof', 'sr', 'sen', 'rep', 
         'rev', 'gov', 'atty', 'supt', 'det', 'rev', 'col','gen', 'lt', 
         'cmdr', 'adm', 'capt', 'sgt', 'cpl', 'maj' ]

  Entities = [ 'dept', 'univ', 'uni', 'assn', 'bros', 'inc', 'ltd', 'co', 
         'corp', 'plc' ]

  Months   = [ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 
         'aug', 'sep', 'oct', 'nov', 'dec', 'sept' ]

  Days     = [ 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun' ]

  Misc     = [ 'vs', 'etc', 'no', 'esp', 'cf' ]

  Streets  = [ 'ave', 'bld', 'blvd', 'cl', 'ct', 'cres', 'dr', 'rd', 'st' ]

  @@abbreviations = Titles + Entities + Months + Days + Streets + Misc

  # Split the passed text into individual sentences, trim these and return
  # as an array. A sentence is marked by one of the punctuation marks ".", "?"
  # or "!" followed by whitespace. Sequences of full stops (such as an
  # ellipsis marker "..." and stops after a known abbreviation are ignored.
  def Sentence.sentences(text)

    text = text.dup

    # initial split after punctuation - have to preserve trailing whitespace
    # for the ellipsis correction next
    # would be nicer to use look-behind and look-ahead assertions to skip
    # ellipsis marks, but Ruby doesn't support look-behind
    text.gsub!( /([\.?!](?:\"|\'|\)|\]|\})?)(\s+)/ ) { $1 << EOS << $2 }

    # correct ellipsis marks and rows of stops
    text.gsub!( /(\.\.\.*)#{EOS}/ ) { $1 }

    # correct abbreviations
    # TODO - precompile this regex?
    text.gsub!( /(#{@@abbreviations.join("|")})\.#{EOS}/i ) { $1 << '.' }

    # split on EOS marker, strip gets rid of trailing whitespace
    text.split(EOS).map { | sentence | sentence.strip }
  end

  # add a list of abbreviations to the list that's used to detect false
  # sentence ends. Return the current list of abbreviations in use.
  def Sentence.abbreviation(*abbreviations)
    @@abbreviations += abbreviations
    @@abbreviations
  end
end
end
end
1 голос
/ 23 февраля 2011

Ответ д-ра Мэннинга является наиболее подходящим, если вы рассматриваете JAVA (и Ruby слишком сложный;)). Это здесь -

Есть разделитель предложений: edu.stanford.nlp.process.DocumentPreprocessor , Попробуйте команду: Java edu.stanford.nlp.process.DocumentPreprocessor /u/nlp/data/lexparser/textDocument.txt

oneTokenizedSentencePerLine.txt. (Это делается через (хорошо, но эвристика) фсм, так быстро; Вы не работает вероятностный анализатор.)

Но небольшое предложение, если мы изменим команду java edu.stanford.nlp.process.DocumentPreprocessor /u/nlp/data/lexparser/textDocument.txt> oneTokenizedSentencePerLine.txt TO java edu.stanford.nlp.process.DocumentPreprocessor -файл /u/nlp/data/lexparser/textDocument.txt> oneTokenizedSentencePerLine.txt . Он будет работать нормально, так как вам нужно указать, какой тип файла будет представлен в качестве входных данных. Так -файл для текстового файла, -html для HTML и т. Д.

1 голос
/ 14 мая 2009

Может быть, попробуйте разделить его на точку, за которой следует пробел, за которым следует заглавная буква? Я не уверен, как найти заглавные буквы, но это был бы образец, на который я бы начал смотреть.

Редактировать: Поиск заглавных букв с помощью Ruby.

Другое Редактирование:

Проверка на пунктуацию, заканчивающуюся предложением после слов, которые не начинаются с заглавных букв.

...