Traditional Vectorization
இப்பொழுது நடைமுறையில் இருக்கும் எம்பெடிங் வெக்டருக்கு முன், என்னென்ன பழமையான நடைமுறைகள் இருந்தது, அதிலிருந்த பிரச்சனைகள் என்னென்ன, எதனால் இந்த எம்பெடிங் நடைமுறை உருவானது என்பதையெல்லாம் இப்பகுதியில் காணலாம். ஒருவருக்கு கோபம் வந்துவிட்டால், மனசுல இருக்குற எல்லாவற்றையும் கொட்டித் தீர்க்கிறேன் என்று அனைத்து வார்த்தைகளையும் போட்டு ஒரு மணி நேரம் பேசுவார்களே! அதைப் போன்றதுதான் இந்த bag of words. அதுவே நாலு வார்த்தை கேட்டாலும் நச்சுன்னு கேட்பார்களே! அது nltk பேக்கேஜ். பயிற்சிக்கு உள்ள எல்லா வார்த்தைகளையும் போட்டு, BoW டிக்க்ஷனரி உருவாக்குகிறது. அதில் nltk பேக்கேஜை பயன்படுத்தினால், முக்கியமான key வார்த்தைகளை மட்டும் போட்டு டிக்க்ஷனரி உருவாக்கப்படுகிறது . இந்த டிக்க்ஷனரி எப்படி உருவாக்கப்பட்டாலும், இதில் உள்ள வார்த்தைகள் ஒரு பைக்குள் போட்டு திணித்து வைத்த மாதிரி தான் இருக்கும். வாக்கியங்களில் இருப்பது போன்று ஒழுங்காக அடுக்கி வைக்கப்பட்டிருக்காது. எனவே தான் இதில் Missing Context என்பது எப்போதும் ஒரு பெரிய பிரச்சனையாகவே இருந்தது. ஒரு சிலர் கோபத்தில் பேசும் பொழுது, அவர்களுக்கு வார்த்தைகள் கோர்வையாகவே வராது. இங்க ஒன்னு அங்க ஒன்னு என்று மாறி மாறி வார்த்தைகளை போடுவார்கள்! என்ன சொல்ல வருகிறார்கள் என்பதே புரியாது! அதைப் போன்றது தான் இந்த மிஸ்ஸிங் கான்டெக்ஸ்ட் பிரச்சனை. “வேண்டாம்!”, “விட்டுவிடு!” என்பவரிடம் போய், “என்ன சொல்றீங்க? புரியல!” எனக் கேட்டால் உடனே, “உறவே வேண்டாம்!”, “ஆளை விட்டுவிடு!” என்று இரண்டிரண்டு வார்த்தைகளாகக் கூறி context-ஐ சற்று புரிய வைக்க முயற்சிப்பார்கள். அதற்கு ஒத்ததுதான் Bi-grams எனும் solution. வார்த்தைகளை இரண்டிரண்டாகவோ, மும்மூன்றாகவோ கோர்த்து டிக்க்ஷனரியை உருவாக்குவதன் மூலம் கான்டெக்ஸ்டை சற்று புரிய வைக்க முயற்சிக்கும்.
இந்த கான்டெக்ஸ்ட் பிரச்சனையோடு சேர்த்து sparse vector பிரச்சனையும் இதில் உள்ளது. அதாவது சண்டையின்போது அந்த பிரச்சனையைப் பற்றி மட்டும் பேசாமல், அதுவரை நடந்த எல்லாப் பிரச்சனைகளையும் இழுத்துப் போட்டு பேச ஆரம்பிப்பார்களே – அதைப் போல! இந்த ஸ்பர்ஸ் வெக்டர் என்பதும் ஒரு வாக்கியத்தைக் குறிக்க இருக்கிற எல்லா வார்த்தைகளையும் பயன்படுத்துகிறது. இதைத் தீர்ப்பதற்காக உருவானதே Dense vectorization எனும் முறை ஆகும். அதாவது நாம் செய்த தவறுகளிலேயே பெரிய தவறை எடுத்துக்கொண்டு பேச ஆரம்பிப்பதன் மூலம், அதன் கீழ் நம்முடைய சிறிய தவறுகள் அனைத்தையும் அடக்கி விடுவார்களே – அதைப் போல! Dense வெக்டர் என்பது இருப்பதிலேயே பெரிய வாக்கியத்தின் அளவை எடுத்துக்கொண்டு அதில் மற்ற சிறிய அளவு வாக்கியங்கள் அனைத்தையும் அடக்க முயலும்.
- Dense வெக்டர் என்பது ஸ்பர்ஸ் வெக்டர் பிரச்சனைக்கு ஒரு நல்ல தீர்வாக இருந்தாலும்,
- Bi-grams, Tri-grams போன்றவை மிஸ்ஸிங் கான்டெக்ஸ்ட் பிரச்சனைக்கு ஒரு நல்ல தீர்வாக அமையவில்லை. இதன் காரணமாக உருவானதே எம்பெடிங் வெக்டர் ஆகும்.
நம் வாயிலிருந்து வரும் ஒவ்வொரு வார்த்தைக்கும், ஆயிரம் அர்த்தம் கண்டுபிடித்து ஞாபகம் வைத்துக் கொள்பவர்களிடமிருந்து, நம்மால் context விஷயத்தில் தப்பவே முடியாது. இந்த வேலையைத்தான் எம்பெடிங் வெக்டர் செய்கிறது. நமது வெக்டரில் இருக்கும் ஒவ்வொரு வார்த்தைக்கும் ஆயிரம் வகையான அர்த்தங்களை features என்ற பெயரில் சேமித்து வைத்துக் கொள்கிறது. இத்தகைய எம்பெடிங் பற்றி ஏற்கனவே விரிவாக பார்த்து விட்டோம். இப்பொழுது மேற்கூறிய பழமையான நடைமுறைகள் அனைத்தையும் சற்று விரிவாகக் காண்போம்.
Bag of words (BoW)
countvectorizer() எனும் ஃபங்ஷன் இதற்கு உதவுகிறது. இங்கு, மொத்தமாக உள்ள வார்த்தைகளின் அளவில் எல்லா வாக்கியங்களும் மாற்றப்பட்டு vectorize செய்யப்படும். ஒவ்வொரு வெக்டரும் அந்தந்த வாக்கியங்களுக்கு ஏற்றார் போல 1 மற்றும் 0-வை அமைக்கும். பின்வரும் உதாரணத்தில் மொத்தமாக 31 வார்த்தைகள் உள்ளதெனில், 31 எலிமென்ட்ஸ் கொண்ட வெக்டர் உருவாக்கப்பட்டு ஒவ்வொரு வாக்கியத்தையும் குறிக்கும்.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import nltk | |
nltk.download('stopwords') | |
nltk.download('punkt') | |
nltk.download('punkt_tab') | |
from sklearn.feature_extraction.text import CountVectorizer | |
paragraph = "Periyar was a social reformer in Tamil Nadu. He founded the Self-Respect Movement. This movement aimed to promote equality and end caste discrimination. Today, he is celebrated as a key figure in the fight for social justice and equality in Tamil Nadu." | |
x = [i for i in paragraph.split('.')] | |
tokens = CountVectorizer() | |
vectors = tokens.fit_transform(x) | |
print(tokens.vocabulary_) | |
print(vectors.toarray()) | |
# tokens = CountVectorizer(stop_words='english') | |
# tokens = CountVectorizer(ngram_range = (2, 2), stop_words='english') |
நிரலுக்கான விளக்கம்:
fit_transform() என்பது வாக்கியங்களை வெக்டர்களாக மாற்ற உதவுகிறது.
vocabulary_ என்பது டிக்சனரியை வெளியிடும்.
{‘periyar’: 19, ‘was’: 30, ‘social’: 24, ‘reformer’: 21, ‘in’: 13, ‘tamil’: 25, ‘nadu’: 18, ‘he’: 12, ‘founded’: 11, ‘the’: 26, ‘self’: 23, ‘respect’: 22, ‘movement’: 17, ‘this’: 27, ‘aimed’: 0, ‘to’: 28, ‘promote’: 20, ‘equality’: 7, ‘and’: 1, ‘end’: 6, ‘caste’: 3, ‘discrimination’: 5, ‘today’: 29, ‘is’: 14, ‘celebrated’: 4, ‘as’: 2, ‘key’: 16, ‘figure’: 9, ‘fight’: 8, ‘for’: 10, ‘justice’: 15}
to_array() என்பது வெக்டரை வெளியிடும்.
[[0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 1 0 0 1 1 0 0 0 0 1]
[0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 1 0 0 1 0 0 0 0]
[1 1 0 1 0 1 1 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 1 0 0]
[0 1 1 0 1 0 0 1 1 1 1 0 1 2 1 1 1 0 1 0 0 0 0 0 1 1 1 0 0 1 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]
இந்த வெக்டரின் அளவு தான் நியூரல் நெட்வொர்க்கின் இன்புட் லேயரில் உள்ள நியூரான்களின் அளவு எனும்போது, இவ்வளவு நீளமான வெக்டரை குறைக்க வேண்டியது அவசியமாகிறது. இதற்கு உதவுவதே NLTK போன்ற பேக்கேஜ்கள் ஆகும். பொதுவாகவே
- பெரிய/சிறிய எழுத்து வித்தியாசம்,
- எழுத்துப் பிழை,
- இலக்கணக்குறி/எழுத்துக்குறி
போன்றவற்றை நீக்கியே டிக்சனரி உருவாக்கப்படும். NLTK- வை பயன்படுத்தும் போது, இன்னும் சில தேவையில்லாத வார்த்தைகளும் நீக்கப்படுகின்றன. ஓவர்ஃபிட்டிங், அண்டர்ஃபிட்டிங் போன்ற தேவையில்லாத பிரச்சனைகளும் தவிர்க்கப்படுகின்றன.
NLTK Package
மேற்கண்ட அதே நிரலில், NLTK பேக்கேஜை இம்போர்ட் செய்து, stop_words= English எனக் கொடுக்கும்போது,
- is, was, in, for, to ஆகிய வார்த்தைகள் நீக்கப்படுகின்றன.
- இரண்டு அல்லது அதற்கும் குறைவான எழுத்துக்களை கொண்ட வார்த்தைகள் நீக்கப்படுகின்றன.
- ஆங்கிலத்தில் அதிகம் பயன்படுத்தப்படும் வார்த்தைகளான a, an, the, and, this போன்றவை நீக்கப்படுகின்றன.
- இதில் உள்ள stemmer, lemmatizer போன்றவை ஒரு சொல்லின் வேர்சொல்லை கண்டறிந்து அதை மட்டுமே சேமிக்கும். ஆகவே dancing, danced, dances போன்றவை dance எனும் ஒற்றை வேர்ச்சொல்லால் சேமிக்கப்பட்டுவிடும்.
மேற்கண்ட அதே நிரலில், கீழ்க்கண்ட வரியை மட்டும் மாற்றி ரன் செய்து பார்க்கவும். அதன் டிக்சனரி மற்றும் வெக்டர் அளவு குறைவதைக் காணலாம்.
tokens = CountVectorizer(stop_words=’english’)
{‘periyar’: 13, ‘social’: 18, ‘reformer’: 15, ‘tamil’: 19, ‘nadu’: 12, ‘founded’: 8, ‘self’: 17, ‘respect’: 16, ‘movement’: 11, ‘aimed’: 0, ‘promote’: 14, ‘equality’: 5, ‘end’: 4, ‘caste’: 1, ‘discrimination’: 3, ‘today’: 20, ‘celebrated’: 2, ‘key’: 10, ‘figure’: 7, ‘fight’: 6, ‘justice’: 9}
[[0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 1 1 0]
[0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 1 0 0 0]
[1 1 0 1 1 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0]
[0 0 1 0 0 1 1 1 0 1 1 0 1 0 0 0 0 0 1 1 1]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]
Solutions for problems in BoW
இம்முறையில் ‘Missing Context’ , ‘sparse vector’ எனும் இரு முக்கியமான பிரச்சனைகள் உள்ளன.
BoW என்பது வெறும் சொற்களை திணித்து வைக்கும் பை மட்டுமே. சொற்கள் அமைந்திருக்கும் வரிசை முறை இதில் கணக்கில் எடுத்துக்கொள்ளப்படுவதில்லை. ஆகவே You are late என்பதற்கும், Are you late என்பதற்கும் ஒரே மாதிரியான வெக்டர் காணப்படும். இதிலிருந்து வாக்கியங்களை interpret செய்யும் போது, அது வேறு விதமாக அர்த்தம் கொள்ளப்பட்டுவிடும் அபாயமே missing context எனும் பிரச்சனை ஆகும்.
அடுத்ததாக, ஒவ்வொரு வாக்கியத்தையும் குறிப்பதற்குப் பயன்படும் வெக்டரில், அந்த முழுக் கட்டுரையில் உள்ள அனைத்து வார்த்தைகளுக்குமான இடம் அமைக்கப்பட்டு, அவை ஜீரோவால் நிரப்பப்பட்டிருப்பதே sparse vector எனும் பிரச்சனை ஆகும். ஆகவே, கட்டுரையின் அளவு அதிகமானால், வெக்டரின் அளவும் அதிகமாகும். வெக்டரின் அளவே features-ன் எண்ணிக்கை என்பதால், தேவையில்லாமல் நிறைய ஃபீச்சர்ஸ் உருவாவதால் வரும் பிரச்சனையே ஸ்பர்ஸ் வெக்டரால் வரும் பிரச்சனை ஆகும்.
இவ்விரண்டு பிரச்சனைகளையும் கையாள்வதற்கு உதவிய, N-Grams மற்றும் Dense வெக்டர் ஆகியவற்றைப் பற்றி அடுத்து காண்போம்.
N-Grams for Missing Context
சொற்களை இரண்டிரண்டாக(bigrams), மும்மூன்றாக(trigrams) இணைத்து டிக்க்ஷனரியை உருவாக்குவதன் மூலம் ஓரளவிற்கு கான்டெக்ஸ்டை கைப்பற்றி விட முடியும். இதுவே N-Grams என்று அழைக்கப்படுகின்றது. முதன் முதலில் இ்வ்வாறெல்லாம் செய்து பார்த்த பின்னரே, எம்பெடிங் வெக்டர்களை உருவாக்கி முழு கான்டெக்ஸ்டையும் கைப்பற்றும் முறை நடைமுறைக்கு வந்தது.
மேற்கண்ட அதே நிரலில், கீழ்க்கண்ட வரியை மட்டும் மாற்றி ரன் செய்து பார்க்கவும்.
tokens = CountVectorizer(ngram_range = (2, 2), stop_words = ‘english’)
இது உருவாக்கும் டிக்சனரி மற்றும் வெக்டர் பின்வருமாறு அமையும்.
{‘periyar social’: 12, ‘social reformer’: 18, ‘reformer tamil’: 14, ‘tamil nadu’: 19, ‘founded self’: 8, ‘self respect’: 16, ‘respect movement’: 15, ‘movement aimed’: 11, ‘aimed promote’: 0, ‘promote equality’: 13, ‘equality end’: 4, ‘end caste’: 3, ‘caste discrimination’: 1, ‘today celebrated’: 20, ‘celebrated key’: 2, ‘key figure’: 10, ‘figure fight’: 7, ‘fight social’: 6, ‘social justice’: 17, ‘justice equality’: 9, ‘equality tamil’: 5}
[[0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 1 0]
[0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 0 0]
[1 1 0 1 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0]
[0 0 1 0 0 1 1 1 0 1 1 0 0 0 0 0 0 1 0 1 1]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]
Dense Vectors for Sparse Issue
ஒவ்வொரு வார்த்தைக்குமான டோக்கனை அப்படியே வெக்டரில் அமைப்பது Distributed representation / dense vector எனப்படும். பின்னர் இருப்பதிலேயே பெரிய வாக்கியத்தின் அளவில், மற்ற அனைத்தும் padding செய்யப்பட்டு விடுகின்றன. இந்த முறைதான் next-word prediction- இல் நாம் பயன்படுத்தியுள்ளது. அங்கு ஜீரோவால் நிரப்புவோம். இங்கு 99 எனும் எண்ணால் நிரப்பியுள்ளோம். காலி இடங்களை நிரப்புவதற்கு எந்த எண்ணை வேண்டுமானாலும் நீங்கள் பயன்படுத்தலாம்.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from sklearn.preprocessing import LabelEncoder | |
import numpy as np | |
paragraph = "Periyar was a social reformer in Tamil Nadu. He founded the Self-Respect Movement. This movement aimed to promote equality and end caste discrimination. Today, he is celebrated as a key figure in the fight for social justice and equality in Tamil Nadu." | |
x = [i for i in paragraph.split('.')] | |
l1 = [] | |
for i in x: | |
l1.append(LabelEncoder().fit_transform(i.split())) | |
padded_arrays = [np.pad(i, (0, max(len(i) for i in l1) – len(i)), 'constant', constant_values=99) for i in l1] | |
print(np.array(padded_arrays)) |
[[ 1 7 3 6 5 4 2 0 99 99 99 99 99 99 99 99 99 99 99]
[ 0 3 4 2 1 99 99 99 99 99 99 99 99 99 99 99 99 99 99]
[ 0 7 1 9 8 6 2 5 3 4 99 99 99 99 99 99 99 99 99]
[ 2 11 13 6 5 3 15 9 12 17 8 10 16 14 4 7 12 1 0]
[99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99]]