개발 공부/NLP

[NLP - 텍스트 전처리] 2. Stemming, Lemmatization, Stopword

sunjungAn 2022. 4. 13. 11:10

어간 추출(Stemming) & 표제어 추출(Lemmatization)

하나의 단어로 일반화시켜서 문서 내의 단어 수를 줄이는 것이다.

⇒ 정규화의 지향점은 갖고 있는 코퍼스로부터 복잡성을 줄이는 것이다.

1. 표제어 추출(Lemmatization)

단어들이 다른 형태를 가지더라도 그 뿌리 단어를 찾아서 단어의 개수를 줄일수 있는지 판단하는 것이다.

2. NLTK의 WordNetLemmatizer

  • 표제어 추출 도구
from nltk.stem import WordNetLemmatizer
nltk.download('wordnet')
lemmatizer = WordNetLemmatizer()

words= ['policy','doing','organization','have', 'going', 'love', 'lives', 'fiy', 'dies', 'watched','has','starting']
print('표제어어 추출출: ', [lemmatizer.lemmatize(word) for word in words])
  • 결과
표제어어 추출출:  ['policy', 'doing', 'organization', 'have', 'going', 'love', 'life', 'fiy', 'dy', 'watched', 'ha', 'starting']
  • 변경사항

lives → life

dies → dy

has → ha

WordNetLemmatizer은 본래 단어의 품사 정보를 알아야 정확한 결과를 얻을 수 있다.

lemmatizer.lemmatize('dies', 'v')
lemmatizer.lemmatize('has', 'v')
  • 결과
die
have

3. 어간 추출(Stemming)

(Poter Algorithm) 어간을 추출하는 규칙을 세워 그 규칙대로 어간을 추출한다.

  • 따라서 이상한 결과가 나올수도 있음
  • 어간 추출 속도는 표제어 추출보다 일반적으로 빠른데, 포터 어간 추출기는 정밀하게 설계되어 정확도가 높으므로 영어 자연어처리에서 어간 추출을 하고자할때 많이 사용됨
  • 그 외로 LancasterStemmer도 있음
from nltk.stem import PorterStemmer
from nltk.stem import LancasterStemmer

porter_stemmer = PorterStemmer()
lancaster_stemmer = LancasterStemmer()

words= ['policy','doing','organization','have', 'going', 'love', 'lives', 'fiy', 'dies', 'watched','has','starting']
print('Poter stemmer: ',[porter_stemmer.stem(w) for w in words])
print('Lancaster stemmer: ',[lancaster_stemmer.stem(w) for w in words])
  • 결과
Poter stemmer:  ['polici', 'do', 'organ', 'have', 'go', 'love', 'live', 'fiy', 'die', 'watch', 'ha', 'start']
Lancaster stemmer:  ['policy', 'doing', 'org', 'hav', 'going', 'lov', 'liv', 'fiy', 'die', 'watch', 'has', 'start']

위 두개의 stemmers에서 적합한 것을 사용하면 됨

4. 어간 추출과 표제어 추출의 차이

  • 표제어어 추출출: ['policy', 'doing', 'organization', 'have', 'going', 'love', 'life', 'fiy', 'dy', 'watched', 'ha', 'starting']
  • Poter stemmer: ['polici', 'do', 'organ', 'have', 'go', 'love', 'live', 'fiy', 'die', 'watch', 'ha', 'start']

⇒ 의미가 동일한 경우에만 같은 단어를 얻기를 원하는 정규화 목적에는 표제어추출이 적합하다.

5. 한국어에서의 어간 추출


  1. 형용사/동사의 활용
    1. ex) 긋다, 그어서, 그어라
  2. 뷸구칙 활용
    1. 듣/다, 들/으러
    2. 등의 어미가 붙으면 어간의 형태가 달라진다.

불용어(Stopword)

큰 의미가 없는 단어 토큰을 제거하는 작업 ⇒ 자주 등장하지만 분석에 도움이 되지 않는 단어들

→ 기존에 불용어 제거를 제공하는 구현된 기능을 사용하는 방법 or 개발자가 직접 설정하는 방법

1. NLTK에서 정의하는 불용어

from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from konlpy.tag import Okt
nltk.download('stopwords')

stop_words_list = stopwords.words('english')
print('불용어 개수: ', len(stop_words_list))
print('불용어 10개 출력: ', stop_words_list[:10])
  • 결과
불용어 개수:  179
불용어 10개 출력:  ['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', "you're"]
example = "Family is not an important thing. It's everything."
stop_words = set(stopwords.words('english'))

word_tokens = word_tokenize(example)

result = []
for word in word_tokens:
  if word not in stop_words:
    result.append(word)
print('불용어 제거 전: ', word_tokens)
print('불용어 제거 후: ', result)
  • 결과
불용어 제거 전:  ['Family', 'is', 'not', 'an', 'important', 'thing', '.', 'It', "'s", 'everything', '.']
불용어 제거 후:  ['Family', 'important', 'thing', '.', 'It', "'s", 'everything', '.']

2. 한국어에서 불용어 제거하기

사용자가 직접 제거하는 법

okt = Okt()
example = "고기를 아무렇게나 구우려고 하면 안 돼. 고기라고 다 같은 게 아니거든. 예컨대 삼겹살을 구울 때는 중요한 게 있지."
stop_words = "를 아무렇게나 구 우려 고 안 돼 같은 게 구울 때 는"

stop_words = set(stop_words.split(' '))
word_tokens = okt.morphs(example)

result = [word for word in word_tokens if not word in stop_words]

print('불용어 제거 전: ', word_tokens)
print('불용어 제거 후: ', result)
  • 결과
불용어 제거 전:  ['고기', '를', '아무렇게나', '구', '우려', '고', '하면', '안', '돼', '.', '고기', '라고', '다', '같은', '게', '아니거든', '.', '예컨대', '삼겹살', '을', '구울', '때', '는', '중요한', '게', '있지', '.']
불용어 제거 후:  ['고기', '하면', '.', '고기', '라고', '다', '아니거든', '.', '예컨대', '삼겹살', '을', '중요한', '있지', '.']

3. 보편적으로 선택할 수 있는 한국어 불용어 리스트

https://www.ranks.nl/stopwords/korean