Определить наиболее вероятные слова из текста без пробелов / комбинированных слов

Как я могу обнаружить и разделить слова из комбинированной строки?

Пример:

"cdimage" -> ["cd", "image"]
"filesaveas" -> ["file", "save", "as"]

person jack    schedule 01.02.2010    source источник
comment
У меня нет никакого опыта в этой области, но вы можете начать с изучения Natural Language Toolkit. nltk.org   -  person Mark Rushakoff    schedule 01.02.2010
comment
И файлы, сохраненные как, могут быть разделены Файлы аве как, НЕ просто Файл Сохранить как. Было бы сложно просто разделить по возможностям слова, если у вас нет специального словарного запаса...   -  person Sparky    schedule 01.02.2010
comment
И [c,dim,age], [cd, i, mage] и т. д., не так просто понять это правильно, не зная контекста. Еще труднее выбрать правильный вариант, когда есть много терминов и аббревиатур, специфичных для предметной области, которые редко встречаются в обычном тексте, но часто встречаются в типичных ожидаемых входных данных. Вероятно, вам нужно обучить алгоритм.   -  person Mark Byers    schedule 01.02.2010
comment
stackoverflow.com/questions/8870261/   -  person Masih    schedule 07.04.2017
comment
Отвечает ли это на ваш вопрос? Нужна помощь в понимании этого алгоритма Python Viterbi   -  person Matthias Winkelmann    schedule 27.12.2019


Ответы (5)


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

WORD_FREQUENCIES = {
    'file': 0.00123,
    'files': 0.00124,
    'save': 0.002,
    'ave': 0.00001,
    'as': 0.00555
}

def split_text(text, word_frequencies, cache):
    if text in cache:
        return cache[text]
    if not text:
        return 1, []
    best_freq, best_split = 0, []
    for i in xrange(1, len(text) + 1):
        word, remainder = text[:i], text[i:]
        freq = word_frequencies.get(word, None)
        if freq:
            remainder_freq, remainder = split_text(
                    remainder, word_frequencies, cache)
            freq *= remainder_freq
            if freq > best_freq:
                best_freq = freq
                best_split = [word] + remainder
    cache[text] = (best_freq, best_split)
    return cache[text]

print split_text('filesaveas', WORD_FREQUENCIES, {})

--> (1.3653e-08, ['file', 'save', 'as'])
person Community    schedule 01.02.2010

Я не знаю какой-либо библиотеки для этого, но реализовать базовую функциональность не составит труда.

  1. Получите список слов, например words в UNIX.
  2. Вставьте содержимое списка слов в файл trie.
  3. Возьмите строку, которую вы хотите разделить, и следуйте по ее пути в дереве. Каждый раз, когда вы достигаете действительного слова, создавайте новую ветвь, которая ищет слово, начиная с точки строки, до которой вы добрались. Как только вы закончите текущую ветку, вернитесь к той, которую вы создали, как при поиске в глубину.
  4. Устраните неоднозначность результирующих списков вручную, используя эвристику или синтаксический анализатор естественного языка.

Пример:

  1. Слово: "filesaveasstring"
  2. Первое допустимое слово — «файл». Попробуйте сопоставить «сохранить». Первое правильное слово "сохранить". Попробуйте сопоставить "asstring". Первое допустимое слово - "как". Попробуйте сопоставить "string". Первое допустимое слово — «строка». Соответствует до конца; поместите [файл сохранить как строку] в список результатов.
  3. Вернитесь к соответствующей "строке" - других возможностей нет. Вернитесь к «астрингу». Первое непосещенное допустимое слово - "задница". Попробуйте сопоставить "tring". Нет возможных совпадений. Вернитесь к «астрингу». Нет возможных совпадений. Вернитесь к «filesaveasstring».
  4. Первый непосещенный матч — «файлы». Попробуйте сопоставить "aveasstring". Первое совпадение — «авеню». Попробуйте сопоставить «asstring» (те же результаты, что и в шагах 2/3), добавить [files ave as string] в список результатов и вернуться к началу.
  5. Попробуйте сопоставить «filesaveasstring». Нет непросмотренных матчей. Сделанный.
  6. Выберите наиболее вероятный вариант из [[сохранить файл как строку] [файлов как строку]], используя эвристический анализатор или анализатор естественного языка.
person Max Shawabkeh    schedule 01.02.2010
comment
Каково время выполнения этого? Я почему-то не могу обобщить эту проблему настолько, чтобы найти ее точную сложность Big-O. - person AllThatICode; 05.08.2016

Я не знаю библиотеки, которая делает это, но это не так сложно написать, если у вас есть список слов:

wordList = file('words.txt','r').read().split()
words = set( s.lower() for s in wordList )

def splitString(s):
    found = []

    def rec(stringLeft, wordsSoFar):
        if not stringLeft:
            found.append(wordsSoFar)
        for pos in xrange(1, len(stringLeft)+1):
            if stringLeft[:pos] in words:
                rec(stringLeft[pos:], wordsSoFar + [stringLeft[:pos]])

    rec(s.lower(), [])
    return found

Это вернет все возможные способы разбить строку на заданные слова.

Пример:

>>> splitString('filesaveas')
[['file', 'save', 'as'], ['files', 'ave', 'as']]
person interjay    schedule 01.02.2010

Можно увидеть этот пример: но он написан на scala. Это может разделить все, что вы хотите, когда предложение не содержит пробела между ними.

Nonspaced-Sentence-Tokenizer

person Abhishek Sengupta    schedule 16.08.2020

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

function findWords(input){
    input = input.toLowerCase().replace(/\s/g, ""); //Strip whitespace

    var index = 0;
    var validWords = [];
    for (var len = input.length; len > 0; len--){ //Go backwards as to favor longer words
        var testWord = input.substr(index, len);
        var dictIndex = _dictionary.indexOf(testWord.replace(/[^a-z\']/g, "")); //Remove non-letters
        if (dictIndex != -1){
            validWords.push(testWord);
            if (len == input.length){
                break; //We are complete
            }
            var nextWords = findWords(input.substr(len, input.length - len)); //Recurse
            if (!nextWords.words.length){ //No further valid words
                validWords.pop();
            }
            validWords = validWords.concat(nextWords.words);
            if (nextWords.complete === true){
                break; //Cascade complete
            }
        }
    }
    return {
        complete:len > 0, //We broke which indicates completion
        words:validWords
    };
}

Примечание. Ожидается, что "_dictionary" будет массивом слов, отсортированных по частоте. Я использую список слов из Project Gutenberg.

person koga73    schedule 28.08.2017