Normalizer

This tutorial is available as an IPython notebook at Malaya/example/normalizer.

[1]:
%%time
import malaya
CPU times: user 4.85 s, sys: 667 ms, total: 5.51 s
Wall time: 4.51 s
[2]:
string1 = 'xjdi ke, y u xsuke makan HUSEIN kt situ tmpt, i hate it. pelikle, pada'
string2 = 'i mmg2 xske mknn HUSEIN kampng tmpat, i love them. pelikle saye'
string3 = 'perdana menteri ke11 sgt suka makn ayam, harganya cuma rm15.50'
string4 = 'pada 10/4, kementerian mengumumkan, 1/100'
string5 = 'Husein Zolkepli dapat tempat ke-12 lumba lari hari ni'
string6 = 'Husein Zolkepli (2011 - 2019) adalah ketua kampng di kedah sekolah King Edward ke-IV'
string7 = '2jam 30 minit aku tunggu kau, 60.1 kg kau ni, suhu harini 31.2c, aku dahaga minum 600ml'

Load normalizer

This normalizer can load any spelling correction model, eg, malaya.spell.probability, or malaya.spell.transformer.

def normalizer(speller = None, **kwargs):
    """
    Load a Normalizer using any spelling correction model.

    Parameters
    ----------
    speller : spelling correction object, optional (default = None)

    Returns
    -------
    result: malaya.normalize.Normalizer class
    """
[3]:
corrector = malaya.spell.probability()
normalizer = malaya.normalize.normalizer(corrector)

normalize

def normalize(
    self,
    string: str,
    check_english: bool = True,
    normalize_text: bool = True,
    normalize_entity: bool = True,
    normalize_url: bool = False,
    normalize_email: bool = False,
    normalize_year: bool = True,
    normalize_telephone: bool = True,
):
    """
    Normalize a string.

    Parameters
    ----------
    string : str
    check_english: bool, (default=True)
        check a word in english dictionary.
    normalize_text: bool, (default=True)
        if True, will try to replace shortforms with internal corpus.
    normalize_entity: bool, (default=True)
        normalize entities, only effect `date`, `datetime`, `time` and `money` patterns string only.
    normalize_url: bool, (default=False)
        if True, replace `://` with empty and `.` with `dot`.
        `https://huseinhouse.com` -> `https huseinhouse dot com`.
    normalize_email: bool, (default=False)
        if True, replace `@` with `di`, `.` with `dot`.
        `husein.zol05@gmail.com` -> `husein dot zol kosong lima di gmail dot com`.
    normalize_year: bool, (default=True)
        if True, `tahun 1987` -> `tahun sembilan belas lapan puluh tujuh`.
        if True, `1970-an` -> `sembilan belas tujuh puluh an`.
        if False, `tahun 1987` -> `tahun seribu sembilan ratus lapan puluh tujuh`.
    normalize_telephone: bool, (default=True)
        if True, `no 012-1234567` -> `no kosong satu dua, satu dua tiga empat lima enam tujuh`

    Returns
    -------
    string: normalized string
    """
[4]:
string = 'boleh dtg 8pagi esok tak atau minggu depan? 2 oktober 2019 2pm, tlong bayar rm 3.2k sekali tau'
[5]:
normalizer.normalize(string)
[5]:
{'normalize': 'boleh datang lapan pagi esok tidak atau minggu depan ? 02/10/2019 14:00:00 , tolong bayar tiga ribu dua ratus ringgit sekali tahu',
 'date': {'8 AM esok': datetime.datetime(2021, 1, 1, 8, 0),
  '2 oktober 2019 2pm': datetime.datetime(2019, 10, 2, 14, 0),
  'minggu depan': datetime.datetime(2021, 1, 7, 19, 33, 47, 65094)},
 'money': {'rm 3.2k': 'RM3200.0'}}
[6]:
normalizer.normalize(string, normalize_entity = False)
[6]:
{'normalize': 'boleh datang lapan pagi esok tidak atau minggu depan ? 02/10/2019 14:00:00 , tolong bayar tiga ribu dua ratus ringgit sekali tahu',
 'date': {},
 'money': {}}

Here you can see, Malaya normalizer will normalize minggu depan to datetime object, also 3.2k ringgit to RM3200

[7]:
print(normalizer.normalize(string1))
print(normalizer.normalize(string2))
print(normalizer.normalize(string3))
print(normalizer.normalize(string4))
print(normalizer.normalize(string5))
print(normalizer.normalize(string6))
print(normalizer.normalize(string7))
{'normalize': 'tak jadi ke , kenapa awak tak suka makan HUSEIN kat situ tempat , saya hate it . pelik lah , pada', 'date': {}, 'money': {}}
{'normalize': 'saya memang-memang tak suka makan HUSEIN kampung tempat , saya love them . pelik lah saya', 'date': {}, 'money': {}}
{'normalize': 'perdana menteri kesebelas sangat suka makan ayam , harganya cuma lima belas ringgit lima puluh sen', 'date': {}, 'money': {'rm15.50': 'RM15.50'}}
{'normalize': 'pada sepuluh hari bulan empat , kementerian mengumumkan , satu per seratus', 'date': {}, 'money': {}}
{'normalize': 'Husein Zolkepli dapat tempat kedua belas lumba lari hari ini', 'date': {}, 'money': {}}
{'normalize': 'Husein Zolkepli ( dua ribu sebelas hingga dua ribu sembilan belas ) adalah ketua kampung di kedah sekolah King Edward keempat', 'date': {}, 'money': {}}
{'normalize': 'dua jam tiga puluh minit aku tunggu kamu , enam puluh perpuluhan satu kilogram kamu ini , suhu hari ini tiga puluh satu perpuluhan dua celsius , aku dahaga minum enam ratus milliliter', 'date': {}, 'money': {}}

Skip spelling correction

Simply pass None to speller to normalizer = malaya.normalize.normalizer. By default it is None.

[8]:
normalizer = malaya.normalize.normalizer(corrector)
without_corrector_normalizer = malaya.normalize.normalizer(None)
[9]:
normalizer.normalize(string2)
[9]:
{'normalize': 'saya memang-memang tak suka makan HUSEIN kampung tempat , saya love them . pelik lah saya',
 'date': {},
 'money': {}}
[10]:
without_corrector_normalizer.normalize(string2)
[10]:
{'normalize': 'saya memang-memang tak suka mknn HUSEIN kampng tmpat , saya love them . pelik lah saya',
 'date': {},
 'money': {}}

Pass kwargs preprocessing

Let say you want to skip to normalize date pattern, you can pass kwargs to normalizer, check original tokenizer implementation at https://github.com/huseinzol05/Malaya/blob/master/malaya/preprocessing.py#L103

[11]:
normalizer = malaya.normalize.normalizer(corrector)
skip_date_normalizer = malaya.normalize.normalizer(corrector, date = False)
[12]:
normalizer.normalize('tarikh program tersebut 14 mei')
[12]:
{'normalize': 'tarikh program tersebut 14/05/2020',
 'date': {'14 mei': datetime.datetime(2020, 5, 14, 0, 0)},
 'money': {}}
[13]:
skip_date_normalizer.normalize('tarikh program tersebut 14 mei')
[13]:
{'normalize': 'tarikh program tersebut empat belas mei',
 'date': {'14 mei': datetime.datetime(2020, 5, 14, 0, 0)},
 'money': {}}

Normalize url

Let say you have an url word, example, https://huseinhouse.com, this parameter going to,

  1. replace :// with empty string.

  2. replace . with dot.

  3. replace digits with string representation.

Simply normalizer.normalize(string, normalize_url = True), default is False.

[14]:
normalizer = malaya.normalize.normalizer()
normalizer.normalize('web saya ialah https://huseinhouse.com')
[14]:
{'normalize': 'web saya ialah https://huseinhouse.com',
 'date': {},
 'money': {}}
[15]:
normalizer.normalize('web saya ialah https://huseinhouse.com', normalize_url = True)
[15]:
{'normalize': 'web saya ialah https huseinhouse dot com',
 'date': {},
 'money': {}}
[16]:
normalizer.normalize('web saya ialah https://huseinhouse02934.com', normalize_url = True)
[16]:
{'normalize': 'web saya ialah https huseinhouse kosong dua sembilan tiga empat dot com',
 'date': {},
 'money': {}}

Normalize email

Let say you have an email word, example, husein.zol05@gmail.com, this parameter going to,

  1. replace :// with empty string.

  2. replace . with dot.

  3. replace @ with di.

  4. replace digits with string representation.

Simply normalizer.normalize(string, normalize_email = True), default is False.

[17]:
normalizer = malaya.normalize.normalizer()
normalizer.normalize('email saya ialah husein.zol05@gmail.com')
[17]:
{'normalize': 'email saya ialah husein.zol05@gmail.com',
 'date': {},
 'money': {}}
[18]:
normalizer = malaya.normalize.normalizer()
normalizer.normalize('email saya ialah husein.zol05@gmail.com', normalize_email = True)
[18]:
{'normalize': 'email saya ialah husein dot zol kosong lima di gmail dot com',
 'date': {},
 'money': {}}

Normalize year

  1. if True, tahun 1987 -> tahun sembilan belas lapan puluh tujuh.

  2. if True, 1970-an -> sembilan belas tujuh puluh an.

  3. if False, tahun 1987 -> tahun seribu sembilan ratus lapan puluh tujuh.

Simply normalizer.normalize(string, normalize_year = True), default is True.

[19]:
normalizer = malaya.normalize.normalizer()
[20]:
normalizer.normalize('$400 pada tahun 1998 berbanding lebih $1000')
[20]:
{'normalize': 'empat ratus dollar pada tahun sembilan belas sembilan puluh lapan berbanding lebih seribu dollar',
 'date': {},
 'money': {'$400': '$400', '$1000': '$1000'}}
[21]:
normalizer.normalize('$400 pada 1970-an berbanding lebih $1000')
[21]:
{'normalize': 'empat ratus dollar pada sembilan belas tujuh puluhan berbanding lebih seribu dollar',
 'date': {},
 'money': {'$400': '$400', '$1000': '$1000'}}
[22]:
normalizer.normalize('$400 pada tahun 1970-an berbanding lebih $1000')
[22]:
{'normalize': 'empat ratus dollar pada tahun sembilan belas tujuh puluhan berbanding lebih seribu dollar',
 'date': {},
 'money': {'$400': '$400', '$1000': '$1000'}}
[23]:
normalizer.normalize('$400 pada tahun 1998 berbanding lebih $1000', normalize_year = False)
[23]:
{'normalize': 'empat ratus dollar pada tahun seribu sembilan ratus sembilan puluh lapan berbanding lebih seribu dollar',
 'date': {},
 'money': {'$400': '$400', '$1000': '$1000'}}

Normalize telephone

  1. if True, no 012-1234567 -> no kosong satu dua, satu dua tiga empat lima enam tujuh.

Simply normalizer.normalize(string, normalize_telephone = True), default is True.

[24]:
normalizer = malaya.normalize.normalizer()
[25]:
normalizer.normalize('no saya 012-1234567')
[25]:
{'normalize': 'no saya kosong satu dua, satu dua tiga empat lima enam tujuh',
 'date': {},
 'money': {}}
[26]:
normalizer.normalize('no saya 012-1234567', normalize_telephone = False)
[26]:
{'normalize': 'no saya 012-1234567', 'date': {}, 'money': {}}

Ignore normalize money

Let say I have a text contains RM 77 juta and I wish to maintain it like that.

[27]:
text = 'Suatu ketika rakyat Malaysia dikejutkan dengan kontrak pelantikan sebanyak hampir RM 77 juta setahun yang hanya terdedah apabila diasak oleh Datuk Seri Anwar Ibrahim.'
[28]:
normalizer = malaya.normalize.normalizer()
[29]:
normalizer.normalize(text)
[29]:
{'normalize': 'Suatu ketika rakyat Malaysia dikejutkan dengan kontrak pelantikan sebanyak hampir tujuh puluh tujuh ringgit juta setahun yang hanya terdedah apabila diasak oleh Datuk Seri Anwar Ibrahim .',
 'date': {},
 'money': {'rm 77': 'RM77'}}
[30]:
normalizer = malaya.normalize.normalizer(money = False)
normalizer.normalize(text, normalize_text = False, check_english = False)
[30]:
{'normalize': 'Suatu ketika rakyat Malaysia dikejutkan dengan kontrak pelantikan sebanyak hampir RM tujuh puluh tujuh juta setahun yang hanya terdedah apabila diasak oleh Datuk Seri Anwar Ibrahim .',
 'date': {},
 'money': {}}
[31]:
normalizer.normalize(text, normalize_text = False, check_english = False)
[31]:
{'normalize': 'Suatu ketika rakyat Malaysia dikejutkan dengan kontrak pelantikan sebanyak hampir RM tujuh puluh tujuh juta setahun yang hanya terdedah apabila diasak oleh Datuk Seri Anwar Ibrahim .',
 'date': {},
 'money': {}}

Normalizing rules

All these rules will ignore if first letter is capital except for normalizing titles.

1. Normalize title,

{
    'dr': 'Doktor',
    'yb': 'Yang Berhormat',
    'hj': 'Haji',
    'ybm': 'Yang Berhormat Mulia',
    'tyt': 'Tuan Yang Terutama',
    'yab': 'Yang Berhormat',
    'ybm': 'Yang Berhormat Mulia',
    'yabhg': 'Yang Amat Berbahagia',
    'ybhg': 'Yang Berbahagia',
    'miss': 'Cik',
}
[32]:
normalizer = malaya.normalize.normalizer()
[33]:
normalizer.normalize('Dr yahaya')
[33]:
{'normalize': 'Doktor yahaya', 'date': {}, 'money': {}}

2. expand x

[34]:
normalizer.normalize('xtahu')
[34]:
{'normalize': 'tak tahu', 'date': {}, 'money': {}}

3. normalize ke -

[35]:
normalizer.normalize('ke-12')
[35]:
{'normalize': 'kedua belas', 'date': {}, 'money': {}}
[36]:
normalizer.normalize('ke - 12')
[36]:
{'normalize': 'kedua belas', 'date': {}, 'money': {}}

4. normalize ke - roman

[37]:
normalizer.normalize('ke-XXI')
[37]:
{'normalize': 'kedua puluh satu', 'date': {}, 'money': {}}
[38]:
normalizer.normalize('ke - XXI')
[38]:
{'normalize': 'kedua puluh satu', 'date': {}, 'money': {}}

5. normalize NUM - NUM

[39]:
normalizer.normalize('2011 - 2019')
[39]:
{'normalize': 'dua ribu sebelas hingga dua ribu sembilan belas',
 'date': {},
 'money': {}}
[40]:
normalizer.normalize('2011.01-2019')
[40]:
{'normalize': 'dua ribu sebelas perpuluhan kosong satu hingga dua ribu sembilan belas',
 'date': {},
 'money': {}}

6. normalize pada NUM (/ | -) NUM

[41]:
normalizer.normalize('pada 10/4')
[41]:
{'normalize': 'pada sepuluh hari bulan empat', 'date': {}, 'money': {}}
[42]:
normalizer.normalize('PADA 10 -4')
[42]:
{'normalize': 'pada sepuluh hari bulan empat', 'date': {}, 'money': {}}

7. normalize NUM / NUM

[43]:
normalizer.normalize('10 /4')
[43]:
{'normalize': 'sepuluh per empat', 'date': {}, 'money': {}}

8. normalize rm NUM

[44]:
normalizer.normalize('RM10.5')
[44]:
{'normalize': 'sepuluh ringgit lima puluh sen',
 'date': {},
 'money': {'rm10.5': 'RM10.5'}}

9. normalize rm NUM sen

[45]:
normalizer.normalize('rm 10.5 sen')
[45]:
{'normalize': 'sepuluh ringgit lima puluh sen',
 'date': {},
 'money': {'rm 10.5': 'RM10.5'}}

10. normalize NUM sen

[46]:
normalizer.normalize('1015 sen')
[46]:
{'normalize': 'sepuluh ringgit lima belas sen',
 'date': {},
 'money': {'1015 sen': 'RM10.15'}}

11. normalize money

[47]:
normalizer.normalize('rm10.4m')
[47]:
{'normalize': 'sepuluh juta empat ratus ribu ringgit',
 'date': {},
 'money': {'rm10.4m': 'RM10400000.0'}}
[48]:
normalizer.normalize('$10.4K')
[48]:
{'normalize': 'sepuluh ribu empat ratus dollar',
 'date': {},
 'money': {'$10.4k': '$10400.0'}}

12. normalize cardinal

[49]:
normalizer.normalize('123')
[49]:
{'normalize': 'seratus dua puluh tiga', 'date': {}, 'money': {}}

13. normalize ordinal

[50]:
normalizer.normalize('ke123')
[50]:
{'normalize': 'keseratus dua puluh tiga', 'date': {}, 'money': {}}

14. normalize date / time / datetime string to datetime.datetime

[51]:
normalizer.normalize('2 hari lepas')
[51]:
{'normalize': 'dua hari lepas',
 'date': {'2 hari lalu': datetime.datetime(2020, 12, 29, 19, 33, 47, 507552)},
 'money': {}}
[52]:
normalizer.normalize('esok')
[52]:
{'normalize': 'esok',
 'date': {'esok': datetime.datetime(2021, 1, 1, 19, 33, 47, 514754)},
 'money': {}}
[53]:
normalizer.normalize('okt 2019')
[53]:
{'normalize': '31/10/2019',
 'date': {'okt 2019': datetime.datetime(2019, 10, 31, 0, 0)},
 'money': {}}
[54]:
normalizer.normalize('2pgi')
[54]:
{'normalize': 'dua pagi',
 'date': {'2 AM': datetime.datetime(2020, 12, 31, 2, 0)},
 'money': {}}
[55]:
normalizer.normalize('pukul 8 malam')
[55]:
{'normalize': 'pukul lapan malam',
 'date': {'pukul 8': datetime.datetime(2020, 12, 8, 0, 0)},
 'money': {}}
[56]:
normalizer.normalize('jan 2 2019 12:01pm')
[56]:
{'normalize': '02/01/2019 12:01:00',
 'date': {'jan 2 2019 12:01pm': datetime.datetime(2019, 1, 2, 12, 1)},
 'money': {}}
[57]:
normalizer.normalize('2 ptg jan 2 2019')
[57]:
{'normalize': 'dua ptg 02/01/2019',
 'date': {'2 PM jan 2 2019': datetime.datetime(2019, 1, 2, 14, 0)},
 'money': {}}

15. normalize money string to string number representation

[58]:
normalizer.normalize('50 sen')
[58]:
{'normalize': 'lima puluh sen', 'date': {}, 'money': {'50 sen': 'RM0.5'}}
[59]:
normalizer.normalize('20.5 ringgit')
[59]:
{'normalize': 'dua puluh ringgit lima puluh sen',
 'date': {},
 'money': {'20.5 ringgit': 'RM20.5'}}
[60]:
normalizer.normalize('20m ringgit')
[60]:
{'normalize': 'dua puluh juta ringgit',
 'date': {},
 'money': {'20m ringgit': 'RM20000000.0'}}
[61]:
normalizer.normalize('22.5123334k ringgit')
[61]:
{'normalize': 'dua puluh dua ribu lima ratus dua belas ringgit tiga ratus tiga puluh empat sen',
 'date': {},
 'money': {'22.512334k ringgit': 'RM22512.334'}}

16. normalize date string to %d/%m/%y

[62]:
normalizer.normalize('1 nov 2019')
[62]:
{'normalize': '01/11/2019',
 'date': {'1 nov 2019': datetime.datetime(2019, 11, 1, 0, 0)},
 'money': {}}
[63]:
normalizer.normalize('januari 1 1996')
[63]:
{'normalize': '01/01/1996',
 'date': {'januari 1 1996': datetime.datetime(1996, 1, 1, 0, 0)},
 'money': {}}
[64]:
normalizer.normalize('januari 2019')
[64]:
{'normalize': '31/01/2019',
 'date': {'januari 2019': datetime.datetime(2019, 1, 31, 0, 0)},
 'money': {}}

17. normalize time string to %H:%M:%S

[65]:
normalizer.normalize('2pm')
[65]:
{'normalize': '14:00:00',
 'date': {'2pm': datetime.datetime(2020, 12, 31, 14, 0)},
 'money': {}}
[66]:
normalizer.normalize('2:01pm')
[66]:
{'normalize': '14:01:00',
 'date': {'2:01pm': datetime.datetime(2020, 12, 31, 14, 1)},
 'money': {}}
[67]:
normalizer.normalize('2AM')
[67]:
{'normalize': '02:00:00',
 'date': {'2am': datetime.datetime(2020, 12, 31, 2, 0)},
 'money': {}}

18. expand repetition shortform

[68]:
normalizer.normalize('skit2')
[68]:
{'normalize': 'sakit-sakit', 'date': {}, 'money': {}}
[69]:
normalizer.normalize('xskit2')
[69]:
{'normalize': 'tak sakit-sakit', 'date': {}, 'money': {}}
[70]:
normalizer.normalize('xjdi2')
[70]:
{'normalize': 'tak jadi-jadi', 'date': {}, 'money': {}}
[71]:
normalizer.normalize('xjdi4')
[71]:
{'normalize': 'tak jadi-jadi-jadi-jadi', 'date': {}, 'money': {}}
[72]:
normalizer.normalize('xjdi0')
[72]:
{'normalize': 'tak jadi', 'date': {}, 'money': {}}
[73]:
normalizer.normalize('xjdi')
[73]:
{'normalize': 'tak jadi', 'date': {}, 'money': {}}

19. normalize NUM SI-UNIT

[74]:
normalizer.normalize('61.2 kg')
[74]:
{'normalize': 'enam puluh satu perpuluhan dua kilogram',
 'date': {},
 'money': {}}
[75]:
normalizer.normalize('61.2kg')
[75]:
{'normalize': 'enam puluh satu perpuluhan dua kilogram',
 'date': {},
 'money': {}}
[76]:
normalizer.normalize('61kg')
[76]:
{'normalize': 'enam puluh satu kilogram', 'date': {}, 'money': {}}
[77]:
normalizer.normalize('61ml')
[77]:
{'normalize': 'enam puluh satu milliliter', 'date': {}, 'money': {}}
[78]:
normalizer.normalize('61m')
[78]:
{'normalize': 'enam puluh satu meter', 'date': {}, 'money': {}}
[79]:
normalizer.normalize('61.3434km')
[79]:
{'normalize': 'enam puluh satu perpuluhan tiga empat tiga empat kilometer',
 'date': {},
 'money': {}}
[80]:
normalizer.normalize('61.3434c')
[80]:
{'normalize': 'enam puluh satu perpuluhan tiga empat tiga empat celsius',
 'date': {},
 'money': {}}
[81]:
normalizer.normalize('61.3434 c')
[81]:
{'normalize': 'enam puluh satu perpuluhan tiga empat tiga empat celsius',
 'date': {},
 'money': {}}

20. normalize laughing pattern

[82]:
normalizer.normalize('dia sakai wkwkwkawkw')
[82]:
{'normalize': 'dia sakai haha', 'date': {}, 'money': {}}
[83]:
normalizer.normalize('dia sakai hhihihu')
[83]:
{'normalize': 'dia sakai haha', 'date': {}, 'money': {}}

21. normalize mengeluh pattern

[84]:
normalizer.normalize('Haih apa lah si yusuff ni . Mama cari rupanya celah ni')
[84]:
{'normalize': 'Aduh apa lah si yusuff ini . Mama cari rupanya celah ini',
 'date': {},
 'money': {}}
[85]:
normalizer.normalize('hais sorrylah syazzz')
[85]:
{'normalize': 'aduh maaf lah syazz', 'date': {}, 'money': {}}