ย
์์ฐ์ด์ฒ๋ฆฌ ๊ณผ์ ์์ ๋ง๋ญ์น ์ ๋จ์ด์ ๊ฐ์๋ฅผ ์ค์ด๊ธฐ ์ํด ํ์ ์ด ์ถ์ถ(lemmatization)๊ณผ ์ด๊ฐ ์ถ์ถ(stemming)๊ธฐ๋ฒ์ ์ฌ์ฉํฉ๋๋ค.
ย
ํ์ ์ด ์ถ์ถ
ํ์ ์ด(lemma)๋ ๋จ์ด์ ๊ธฐ๋ณธํ์ ๋ปํฉ๋๋ค. โdiveโ๋ผ๋ ๋์ฌ๋ฅผ ํ ๋ฒ ๋ถ์ํด๋ด
์๋ค. ์ด ๋์ฌ๋ diving, dove, dived, dives ๋ฑ ๋ฌธ์ฅ ์์์์ ์ญํ ์ ๋ฐ๋ผ ๋ค์ํ ํํ๋ก ๋ณํ๋ฉ๋๋ค. โbeโ๋ผ๋ ๋จ์ด๋ฅผ ๋ ์๋ก ๋ค์๋ฉด am, was, are, is ๋ฑ ์ฌ๋ฌ๊ฐ์ง์ ๋ชจ์ต๋ค๋ก ๋ํ๋ฉ๋๋ค. ์ด๋, dive์ be๊ฐ ๊ฐ๊ฐ์ ๋ชจ๋ ๋จ์ด๋ค์ ๊ธฐ๋ณธํ, ์ฆ ํ์ ์ด์ธ ๊ฒ๋๋ค. ์ด๋ ํ ํฐ๋ค์ ์ด๋ฌํ ํ์ ์ด๋ก ๋ฐ๊พธ๋ฉฐ ๋ฒกํฐ ํํ์ ์ฐจ์์ ์ถ์ํ๋ ์ด ๊ณผ์ ์ ํ์ ์ด ์ถ์ถ์ด๋ผ๊ณ ํฉ๋๋ค.
ย
import spacy nlp = spacy.load('en') doc = nlp(u"he was running late") for token in doc: print('{} --> {}'.format(token, token.lemma_)) #format() ํจ์๋ ๋ฐ์ดํ ์ {} ์์ ์ง์ ํด์ค ๋ณ์๋ค์ ์ฐจ๋ก๋๋ก ๋ฃ์ด์ค๋๋ค.
ย
โhe was running lateโ๋ผ๋ ๋ฌธ์ฅ์ ํ ํฐํํ์ฌ ์ป์ ํ ํฐ๋ค์ token, ๊ทธ๋ฆฌ๊ณ ๊ทธ ํ ํฐ๋ค์ด ํ์ ์ด ์ถ์ถ ๊ณผ์ ๊ฑฐ์น ๊ฒฐ๊ณผ๋ฅผ token.lemma_๋ก ๋ํ๋
๋๋ค. ์ฝ๋๋ฅผ ๋๋ฆฌ๋ฉด ์๋์ ๊ฐ์ด ์ถ๋ ฅ๋ฉ๋๋ค.
ย
he --> he was --> be running --> run late --> late
ย
์ด๋ ํ์ ์ด ์ถ์ถ์์ ์ฃผ์ํด์ผํ ์ ์, ๋จ์ด์ ํ์ฌ ์ ๋ณด๋ ํํ์ ์ ๋ณด๋ฅผ ์์์ผ ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋ค๋ ๊ฒ์
๋๋ค. ์ ์ฝ๋์์ ์ฌ์ฉํ spaCy๋ ์ด๋ฏธ ๋ง์ ๋จ์ด๋ค์ ๊ธฐ๋ณธํ์ด ์ ์๋ WordNet ์ฌ์ ์ ์ฌ์ฉํ์ฌ ํ์ ์ด๋ฅผ ์ถ์ถํฉ๋๋ค. NLTK(Natural Language ToolKit)์์ ์ ๊ณตํ๋ ํ์ ์ด ์ถ์ถ ๋๊ตฌ์ธ WordNetLemmatizer์ ๊ฐ์ ๊ฒฝ์ฐ์๋ ๋จ์ด๋ฅผ ์
๋ ฅํ ๋ ๊ทธ ๋จ์ด์ ํ์ฌ๋ฅผ ํจ๊ป ์
๋ ฅํด์ฃผ์ด, ํ์ฌ๊ฐ ๋ณด์กด๋ ํ์ ์ด๋ฅผ ์ถ๋ ฅํด์ค๋ค๊ณ ํฉ๋๋ค.
ย
์ด๊ฐ ์ถ์ถ
์ด๊ฐ(stem)์ ๋จ์ด์์ ๋ณํ์ง ์๋ ๋ถ๋ถ์ ๋ปํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฌธ์ฅ ์ ์ด๋ฌํ ์ด๊ฐ๋ค์ ์ถ์ถํด๋ด๋ ๊ธฐ๋ฒ์ ์ด๊ฐ ์ถ์ถ์ด๋ผ๊ณ ํฉ๋๋ค. ์ด๋, ์ด๊ฐ ์ถ์ถ์ ๋จ์ํ ์๋์ผ๋ก ์ ํ ๊ท์น์ ์ฌ์ฉํ์ฌ ๋จ์ด์ ๋์ ์๋ผ ๊ฒฐ๊ณผ๋ฅผ ๋์ถํด๋ด๋๋ฐ, ์ด ๊ท์น์ด ์ธ์ ๋ชจ๋ ๋จ์ด๋ค์ ๋ง๊ฒ ์ ์ฉ๋ ์๋ ์๊ธฐ ๋๋ฌธ์ ์ ํ๋๊ฐ ๋ค์ ๋ถ์กฑํ๋ค๋ ๋จ์ ์ด ์์ต๋๋ค.
ย
์ด๊ฐ ์ถ์ถ๊ธฐ๋ก๋ Porter์ Snowball์ด ์ ๋ช
ํ๋ฐ, ์๋ ์ฝ๋๋ Porter๋ฅผ ์ด์ฉํ์ฌ This was not the map we found in Billy Bones's chest, but an accurate copy, complete in all things--names and heights and soundings--with the single exception of the red crosses and the written notes.๋ผ๋ ๋ฌธ์ฅ์ ์ด๊ฐ ์ถ์ถ ๊ธฐ๋ฒ์ ์ฌ์ฉํ ๊ฒฝ์ฐ์
๋๋ค.
ย
import nltk from nltk.stem import PorterStemmer from nltk.tokenize import word_tokenize s = PorterStemmer() text = "This was not the map we found in Billy Bones's chest, but an accurate copy, complete in all things--names and heights and soundings--with the single exception of the red crosses and the written notes." words = word_tokenize(text) print(words) #๋ฌธ์ฅ์ ๋จ์ด๋ค์ ๋๋ ['This', 'was', 'not', 'the', 'map', 'we', 'found', 'in', 'Billy', 'Bones', "'s", 'chest', ',', 'but', 'an', 'accurate', 'copy', ',', 'complete', 'in', 'all', 'things', '--', 'names', 'and', 'heights', 'and', 'soundings', '--', 'with', 'the', 'single', 'exception', 'of', 'the', 'red', 'crosses', 'and', 'the', 'written', 'notes', '.'] #๊ฐ ๋จ์ด๋ค์ด ์ด๊ฐ ์ถ์ถ ๊ณผ์ ์ ๊ฑฐ์น ๊ฒฐ๊ณผ [s.stem(w) for w in words] ['thi', 'wa', 'not', 'the', 'map', 'we', 'found', 'in', 'billi', 'bone', "'s", 'chest', ',', 'but', 'an', 'accur', 'copi', ',', 'complet', 'in', 'all', 'thing', '--', 'name', 'and', 'height', 'and', 'sound', '--', 'with', 'the', 'singl', 'except', 'of', 'the', 'red', 'cross', 'and', 'the', 'written', 'note', '.']
ย
์ฝ๋ ์ ์ด๊ฐ ์ถ์ถ ๊ณผ์ ์ ๊ฑฐ์น ๊ฒฐ๊ณผ์์ ๋ณผ ์ ์๋ฏ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ถ๋ ฅ๋ ๋จ์ด๋ค๋ ์์ง๋ง ํ๋ฆฐ ๋จ์ด๋ค๋ ๊ต์ฅํ ๋ง์ต๋๋ค. ์ด๊ฐ ์ถ์ถ์ ํ์ ์ด ์ถ์ถ๊ณผ ๋ฌ๋ฆฌ ํ์ฌ์ ๋ณด์กด๋ ์ด๋ฃจ์ด์ง์ง ์๋ค๋ ๊ฒ๋ ์ ์ ์์ต๋๋ค. ์ ํ๋๋ ํ์ ์ด ์ถ์ถ๋ณด๋ค ๋ถ์กฑํ ๋์ ์ถ์ ๊ณผ์ ์ ๋น๊ต์ ๋นจ๋ฆฌ ์ํํ๋ค๋ ์ฅ์ ์ ๊ฐ์ง๋๋ค.
ย
์ด์ ๊ธ ์ฝ๊ธฐ
๋ค์ ๊ธ ์ฝ๊ธฐ