Question

Je travaille sur une solution pour diviser les longues lignes de Khmer (la langue cambodgienne) en mots (en UTF-8). Khmer n'utilise pas d'espaces entre les mots. Il y a quelques solutions là-bas, mais ils sont loin d'être suffisant ( ici et ), et ces projets sont tombés au bord du chemin.

Voici une ligne échantillon de Khmer qui doit être partagé (ils peuvent être plus que cela):

??? ????? ??? ????? ??? ????? ??? ?????? ??? ??????? ??? ????? ??? ???? ??? ????? ???? ?????????? ??? ??? ???? ?????? ?? ??? ??????? ??? ?????? ????????????? ???? ???? ???.

Le but de créer une solution viable qui sépare les mots khmers est double: elle encouragera ceux qui ont utilisé héritage khmer polices (non Unicode) pour convertir vers Unicode (qui a de nombreux avantages), et permettra héritage des polices khmères à importer en Unicode pour être utilisé avec un vérificateur d'orthographe rapidement (plutôt que d'aller manuellement à travers et mots de séparation qui, avec un document volumineux, peut prendre très longtemps).

Je ne ai pas besoin de 100% de précision, mais la vitesse est importante (d'autant plus que la ligne qui doit être divisé en mots khmers peut être assez long). Je suis ouvert aux suggestions, mais actuellement je un grand corpus de mots khmers qui sont correctement split (avec un espace insécable), et je l'ai créé un fichier de dictionnaire de probabilité de mot (frequency.csv) à utiliser comme un dictionnaire pour la mot séparateur.

J'ai trouvé ce code python qui utilise le algorithme de Viterbi et il fonctionne soi-disant rapide.

import re
from itertools import groupby

def viterbi_segment(text):
    probs, lasts = [1.0], [0]
    for i in range(1, len(text) + 1):
        prob_k, k = max((probs[j] * word_prob(text[j:i]), j)
                        for j in range(max(0, i - max_word_length), i))
        probs.append(prob_k)
        lasts.append(k)
    words = []
    i = len(text)
    while 0 < i:
        words.append(text[lasts[i]:i])
        i = lasts[i]
    words.reverse()
    return words, probs[-1]

def word_prob(word): return dictionary.get(word, 0) / total
def words(text): return re.findall('[a-z]+', text.lower()) 
dictionary = dict((w, len(list(ws)))
                  for w, ws in groupby(sorted(words(open('big.txt').read()))))
max_word_length = max(map(len, dictionary))
total = float(sum(dictionary.values()))

J'ai aussi essayé d'utiliser le code source Java de l'auteur de cette page: segmentation du texte :. césure de mots d'un dictionnaire mais il a couru trop lent pour être d'une quelconque utilité (parce que mon dictionnaire de mots de probabilité a plus de 100k termes ...)

Et voici une autre option en python Detect de texte mots les plus probables sans espaces / mots combinés :

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'])

Je suis un newbee quand il s'agit de python et je suis vraiment nouveau à toute la programmation réelle (en dehors des sites), donc faire preuve de patience. Quelqu'un at-il des options qu'ils se sentent fonctionnent bien?

Était-ce utile?

La solution

La bibliothèque de soins intensifs (qui a python et liaisons Java) présente un la classe de DictionaryBasedBreakIterator qui peut être utilisé pour cela.

Autres conseils

The python with example filesaveas appears to recurse through the entire input string (for i in xrange(1, len(text) + 1)), stuffing the best results into the cache along the way; at each potential word, it then starts looking at the next word (which will in turn look at the word after that, and so on), and if that second word doesn't look very good, it won't save that particular one. It feels like O(N!) runtime, where N is the length of the input string.

Super clever, but probably horrible for anything but simple tasks. What's the longest Khmer word you've got? I'm hoping < 20 characters.

Maybe if you feed input into that example 20 characters at a time you can keep the runtime down to something approaching reasonable. Feed in the first 20 chars, suck off the first word, and then feed in the remaining input. If you re-use the cache it might do something silly like store partial words along the way.

On a completely different tack, how many Khmer words are formed by concatenating two or more legal Khmer words? (similar to 'penknife' or 'basketball') If not too many, it might make sense to create a set of dictionaries, segregated by length of word, mapping from word to probability of use.

Say, the longest Khmer word is 14 chars long; feed in 14 characters of input into the len14 dictionary, store the probability. Feed in 13 characters into len13, store the probability. Feed in 12 characters ... all the way down to 1 into len1. Then pick the interpretation with the highest probability, save the word, strip off that many characters, and try again.

So it won't fail badly for inputs like "I" vs "Image", maybe longer inputs should have automatically inflated probabilities?

Thanks for the fun question ;) I didn't know of any languages like this, pretty cool.

I think this is a good idea, as it is.

I suggest you, when you have some experience with it, you add some rules, that can be very specific, for example, depending on word before, depending on word after, depending on surrounding words, depending on a sequence of words before the current word, just to enumerate the most frequent ones. You can find a set of rules in gposttl.sf.net project, which is a pos tagging project, in the file data/contextualrulefile.

Rules should be used AFTER the statistics evaluation is finished, they make some fine tuning, and can improve accuracy remarkably.

scroll top