Tokenizing Thai language

Post date: Nov 1, 2016 2:35:35 PM

Unicode tokenizing packages

There are some solutions I'm aware of:

  • Elastic 5.0 Tokenizer API. It seems a very convenient solution with Github page. I haven't tested the API yet.
  • Michael Partridge use multi-layer perceptron (implemented in Theano, python) to train Thai tokenizer model, maintained in Github. He also tried using other techniques like CRF (all in python) for tokenizing Thai language.
  • pythai is based on libthai (libthai on Github), a Thai language support and utility package created in Thai linux community. It's maintained in Github. What I don't like is the complexity to install the package on Mac--this stackoverflow post elaborates how to use it on Mac. But the bright side is that it might be convenient for linux server.
  • Blog by Nor Thanapon also gives good overview of Thai tokenizing tools in Java.
  • PyICU is a Python extension wrapping IBM’s International Components for Unicode C++ library (ICU). It's mature, consistently maintained (Github page) and open source.

Tokenizing Thai language using PyICU

So, PyICU is the package of my choice because it's mature, open source and convenient to install.

Installing PyICU

Credits to Thodsaporn (Boated) Chay-intr for providing an excellent installation note here:

$ brew install icu4c
$ env LDFLAGS="-L/usr/local/opt/icu4c/lib" CPPFLAGS="-I/usr/local/opt/icu4c/include" DYLD_LIBRARY_PATH="-L/usr/local/opt/icu4c/lib" pip install pyicu

For python3, change pip to pip3.

Code example

Here is a code example for Thai tokenizing by Chad Humphries. Credits to วรรณพงษ์ ภัททิยไพบูลย์ for providing the package information and code examples.

import PyICU
def isThai(chr):
    cVal = ord(chr)
    if(cVal >= 3584 and cVal <= 3711):
        return True
    return False
def warp(txt):
    print txt
    bd = PyICU.BreakIterator.createWordInstance(PyICU.Locale("th"))
    bd.setText(txt)
    lastPos = bd.first()
    retTxt = ""
    try:
        while(1):
            currentPos = bd.next()
            retTxt += txt[lastPos:currentPos]
            #Only thai language evaluated
            if(isThai(txt[currentPos-1])):
                if(currentPos < len(txt)):
                    if(isThai(txt[currentPos])):
                        #This is dummy word seperator   
                        retTxt += "|"
            lastPos = currentPos
    except StopIteration:
        pass
        #retTxt = retTxt[:-1]
    return retTxt
if __name__ == "__main__":
    text = u"ปวดหัวคงจะเป็นอาการที่มนุษย์รู้สึกบ่อยที่สุดในบรรดาอาการทั้งหลายเพราะหัวอยู่ใกล้สมองอันเป็นที่รับรู้ ที่จริงอาการอื่นๆ มันก็คงจะมีมากเหมือนกัน เช่น ปวดแข้ง ปวดขา ปวดนิ้วเท้า แต่เนื่องจากมันอยู่ไกลที่รับรู้ จึงไม่ค่อยคำนึงถึง ปวดหัวเกือบทั้งหมดเกิดจากอาการเครียด เช่น อดนอน ทำงานใช้ความคิดมาก มีอารมณ์ เช่น รถติด วิตกกังวล โกรธ เกลียด"
    tokens = warp(text.replace(' ',''))
    print tokens

Results:

>>> ปวด|หัว|คงจะ|เป็น|อาการ|ที่|มนุษย์|รู้สึก|บ่อย|ที่สุด|ใน|บรรดา|อาการ|ทั้ง|หลาย|เพราะ|หัว|อยู่|ใกล้|สมอง|อัน|เป็น|ที่|รับ|รู้|ที่|จริง|อา|กา|รอื่นๆ|มัน|ก็|คงจะ|มี|มาก|เหมือน|กัน|เช่น|ปวด|แข้ง|ปวด|ขา|ปวด|นิ้ว|เท้า|แต่|เนื่องจาก|มัน|อยู่|ไกล|ที่|รับ|รู้|จึง|ไม่|ค่อย|คำนึง|ถึง|ปวด|หัว|เกือบ|ทั้งหมด|เกิด|จาก|อาการ|เครียด|เช่น|อด|นอน|ทำงาน|ใช้|ความ|คิดมาก|มี|อารมณ์|เช่น|รถ|ติด|วิตก|กังวล|โกรธ|เกลียด

Of course, there are some interesting mis-tokenizing like "อา|กา|รอื่นๆ" (อาการ|อื่นๆ) or "ปวด|หัว" (ปวดหัว should be collocation).