본문 바로가기

딥러닝/딥러닝을 이용한 자연어처리 입문

[딥러닝 NLP] 02. 텍스트 전처리

# 02-01 토큰화

1. 단어 토큰화(word tokenization)

-토큰(token): 의미있는 단위

-토큰화(tokenization): 코퍼스(corpus)에서 토큰이라 불리는 단위로 나누는 작업

-단어 토큰화: 토큰의 기준을 단어로 하는 경우

 

2. 영어 토큰화 도구들

- NLTK의 word_tokenize: Don't를 Do와 n't로, Jone's를 Jone과 's로 분류

- NLTK의 wordPunctTokenizer: 구두점을 별도로 분류 (Don't를 Don와 '와 t로, Jone's를 Jone과 '와 s로 분류)

- 케라스의 text_to_word_sequence: 기본적으로  모든 알파벳을 소문자로 바꾸면서 마침표나 컴마, 느낌표 등의 구두점을 제거하지만 don't나 jone's와 같은 경우 아포스트로피는 보존

 

3. 문장 토큰화

-문장 토큰화(sentence tokenization): 갖고있는 코퍼스 내에서 문장 단위로 구분하는 작업

-NLTK의 sent_tokenize: 단순히 마침표를 구분자로 하여 문장을 구분하지 않음

-한국어는 KSS의 split_sentences 사용 추천

 

4. 한국어가 토큰화 어려운 이유

-어절토큰화가 아닌 형태소토큰화(자립형태소, 의존형태소로 분류)

-띄어쓰기로 간단히 구분 불가

 

5. 품사 태깅

-품사 태깅(part-of-speech tagging): 각 단어가 어떤 품사로 쓰였는지를 구분하는 지표

- NLTK에서는 Penn Treebank POS Tags라는 기준을 사용하여 품사를 태깅

- Penn Treebank POS Tags (PRP: 인칭 대명사, VBP: 동사, RB: 부사, VBG: 현재부사, IN: 전치사, NNP: 고유 명사, NNS: 복수형 명사, CC: 접속사, DT: 관사)

-한국어 형태소 분석기: KoNLPy(코엔엘파이)의 Okt(Open Korea Text), 메캅(Mecab), 코모란(Komoran), 한나눔(Hannanum), 꼬꼬마(Kkma)

    -각 형태소 분석기는 공통적으로 다음 메소드들을 지원

    1) morphs : 형태소 추출
    2) pos : 품사 태깅(Part-of-speech tagging)
    3) nouns : 명사 추출

 

# 02-02 정제와 정규화

-정제(cleaning) : 갖고 있는 코퍼스로부터 노이즈 데이터를 제거

-정규화(normalization) : 표현 방법이 다른 단어들을 통합시켜서 같은 단어로 만듦

-대소문자 통합: 결국 예외사항 고려하지 않고 모든 코퍼스를 소문자로 바꾸는 것이 종종 더 실용적인 해결책이 되기도 함

-노이즈데이터: 분석 목적에 맞지 않는 데이터(주로 등장빈도가 적은 단어, 길이가 짧은 단어 등)

 

# 02-03 어간추출과 표제어추출

1. 표제어추출(Lemmatization)

-표제어(Lemma): 단어들이 다른 형태를 가지더라도, 그 뿌리 단어를 찾아가서 단어의 개수를 줄일 수 있는지 판단 (Ex. am, are, is의 표제어는 be)

-형태학적 파싱: 어간(stem)과 접사(affix)로 분리하는 작업

-NLTK의 WordNetLemmatizer로 표제어추출 작업 수행시, 본래 단어의 품사 정보를 알아야만 정확한 결과를 얻을 수 있음. 다음과 같이 표제어 추출기에 단어의 품사 정보를 알려줄 수 있음

    - lemmatizer.lemmatize('dies', 'v')

 

2. 어간추출(Stemming)

-어간을 추출하는 작업으로, 정해진 규칙만 보고 단어의 어미를 어림짐작해서 자름

-포터 알고리즘(Porter Algorithm): 정밀하게 설계되어 정확도가 높으므로 영어 자연어 처리에서 가장 준수한 선

-랭커스터 스태머(Lancaster Stemmer) 알고리즘

-사용하고자 하는 코퍼스에 스태머를 적용해보고 어떤 스태머가 해당 코퍼스에 적합한지를 판단한 후에 사용

 

Stemming
am → am
the going → the go
having → hav

Lemmatization
am → be
the going → the going
having → have

 

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

-활용: 용언(동사, 형용사)의 어간(stem)이 어미(ending)를 가지는 일

-어간의 모습이 일정하다면 규칙 활용, 어간이나 어미의 모습이 변하면 불규칙 활용

# 02-04 불용어

-불용어(Stopword) : 문장에서는 자주 등장하지만 실제 의미 분석을 하는데는 거의 기여하는 바가 없는 단어

-NLTK 패키지를 이용해 불용어 제거 가능

-보편적인 한국어 불용어 리스트 https://www.ranks.nl/stopwords/korean

 

Korean Stopwords

 

www.ranks.nl

 

# 02-05 정규표현식

1. 정규표현식 문법

특수문자 설명

. 한 개의 임의의 문자를 나타냅니다. (줄바꿈 문자인 \n는 제외)
? 앞의 문자가 존재할 수도 있고, 존재하지 않을 수도 있습니다. (문자가 0개 또는 1개)
* 앞의 문자가 무한개로 존재할 수도 있고, 존재하지 않을 수도 있습니다. (문자가 0개 이상)
+ 앞의 문자가 최소 한 개 이상 존재합니다. (문자가 1개 이상)
^ 뒤의 문자열로 문자열이 시작됩니다.
$ 앞의 문자열로 문자열이 끝납니다.
{숫자} 숫자만큼 반복합니다.
{숫자1, 숫자2} 숫자1 이상 숫자2 이하만큼 반복합니다. ?, *, +를 이것으로 대체할 수 있습니다.
{숫자,} 숫자 이상만큼 반복합니다.
[ ] 대괄호 안의 문자들 중 한 개의 문자와 매치합니다. [amk]라고 한다면 a 또는 m 또는 k 중 하나라도 존재하면 매치를 의미합니다. [a-z]와 같이 범위를 지정할 수도 있습니다. [a-zA-Z]는 알파벳 전체를 의미하는 범위이며, 문자열에 알파벳이 존재하면 매치를 의미합니다.
[^문자] 해당 문자를 제외한 문자를 매치합니다.
l AlB와 같이 쓰이며 A 또는 B의 의미를 가집니다.

문자규칙 설명

\\\ 역 슬래쉬 문자 자체를 의미합니다
\\d 모든 숫자를 의미합니다. [0-9]와 의미가 동일합니다.
\\D 숫자를 제외한 모든 문자를 의미합니다. [^0-9]와 의미가 동일합니다.
\\s 공백을 의미합니다. [ \t\n\r\f\v]와 의미가 동일합니다.
\\S 공백을 제외한 문자를 의미합니다. [^ \t\n\r\f\v]와 의미가 동일합니다.
\\w 문자 또는 숫자를 의미합니다. [a-zA-Z0-9]와 의미가 동일합니다.
\\W 문자 또는 숫자가 아닌 문자를 의미합니다. [^a-zA-Z0-9]와 의미가 동일합니다.

 

2. 모듈함수

re.compile() 정규표현식을 컴파일하는 함수입니다. 다시 말해, 파이썬에게 전해주는 역할을 합니다. 찾고자 하는 패턴이 빈번한 경우에는 미리 컴파일해놓고 사용하면 속도와 편의성면에서 유리합니다.
re.search() 문자열 전체에 대해서 정규표현식과 매치되는지를 검색합니다.
re.match() 문자열의 처음이 정규표현식과 매치되는지를 검색합니다.
re.split() 정규 표현식을 기준으로 문자열을 분리하여 리스트로 리턴합니다.
re.findall() 문자열에서 정규 표현식과 매치되는 모든 경우의 문자열을 찾아서 리스트로 리턴합니다. 만약, 매치되는 문자열이 없다면 빈 리스트가 리턴됩니다.
re.finditer() 문자열에서 정규 표현식과 매치되는 모든 경우의 문자열에 대한 이터레이터 객체를 리턴합니다.
re.sub() 문자열에서 정규 표현식과 일치하는 부분에 대해서 다른 문자열로 대체합니다.

 

# 02-06 정수 인코딩

* 정수 인코딩(Integer Encoding): 자연어처리에서 텍스트를 숫자로 바꾸는 것

1. dictionary 사용하기

-단어 토큰화를 진행하며 파이썬의 딕셔너리 구조로 단어를 키(key)로, 단어에 대한 빈도수가 값(value)으로 저장

-빈도수가 높은 상위 n개 단어만 저장

- Out-Of-Vocabulary(단어 집합에 없는 단어) 문제: 단어 집합에 존재하지 않는 단어들이 생기는 상황

-OOV 문제 해결법: 'OOV'란 단어를 새롭게 추가하고, 단어 집합에 없는 단어들은 'OOV'의 인덱스로 인코딩

 

2. Counter 사용하기

-파이썬의 Counter() 입력으로 단어 리스트를 주면 중복을 제거하고 단어의 빈도수를 기록

- 단어를 키(key)로, 단어에 대한 빈도수가 값(value)으로 저장되므로 단어를 입력하면 빈도수를 리턴

- most_common() : 상위 빈도수를 가진 주어진 수의 단어만을 리턴

 

3. NLTK의 FreqDist 사용하기

- NLTK의 빈도수 계산 도구인 FreqDist() 는 파이썬의 Counter()와 똑같은 기능

- enumerate() : 순서가 있는 자료형(list, set, tuple, dictionary, string)을 입력으로 받아 인덱스를 순차적으로 함께 리턴

 

4. 케라스의 텍스트 전처리

- tokenizer = Tokenizer()

- tokenizer.fit_on_texts() : 입력한 텍스트로부터 단어 빈도수가 높은 순으로 낮은 정수 인덱스를 부여

- tokenizer.word_index : 각 단어에 인덱스가 어떻게 부여되었는지

tokenizer.word_counts : 각  단어가 카운트를 수행하였을 때 몇 개였는지

- tokenizer.texts_to_sequences() : 입력으로 들어온 코퍼스에 대해서 각 단어를 이미 정해진 인덱스로 변환

- tokenizer = Tokenizer(num_words=숫자) : 빈도수가 높은 상위 몇 개의 단어만 사용하겠다고 지정, 실제 적용은 texts_to_sequences를 사용할 때만 적용됨

- Tokenizer의 인자 oov_token : 케라스 Tokenizer는  기본적으로 단어 집합에 없는 단어인 OOV에 대해서는 단어를 정수로 바꾸는 과정에서 아예 단어를 제거하므로, 단어 집합에 없는 단어들을 OOV로 간주하여 보존하기 위한 방법. 'OOV'의 인덱스를 기본적으로 1로 함

  tokenizer = Tokenizer(num_words = vocab_size + 2, oov_token = 'OOV')

 

# 02-07 패딩

* 패딩(Padding) : 병렬 연산을 위해서 여러 문장의 길이를 임의로 동일하게 맞춰주는 작업. 데이터에 특정 값을 채워서 데이터의 크기(shape)를 조정하는 것

1. Numpy로 패딩하기

-모든 문장의 길이를 가장 긴 문장의 길이인 n에 맞추어 숫자0으로 채워줌

-제로 패딩 : 숫자 0을 채워서 패딩하는 것

 

2. 케라스 전처리 도구로 패딩하기

- pad_sequences() : 기본적으로 문서의 앞에 0으로 채우기 때문에 뒤에 0을 채우고 싶다면 인자로 padding='post' 주기

- 꼭 가장 긴 문서의 길이를 기준으로 해야하는 것은 아니며, 가령 평균보다 너무 긴 문서가 있다면 길이에 제한을 두고 패딩할 수 있음.

- maxlen의 인자로 정수를 주면, 해당 정수로 모든 문서의 길이를 동일하게 함. 만약, 데이터가 손실될 경우에 앞의 단어가 아니라 뒤의 단어가 삭제되도록 하고싶다면 truncating='post'를 사용

- pad_sequences의 인자로 value를 사용하면 0이 아닌 다른 숫자로 패딩이 가능

  padded = pad_sequences(encoded, padding='post', value=last_value)

# 02-08 원-핫 인코딩

1. 원-핫 인코딩이란?

-단어 집합(vocabulary) : 서로 다른 단어들의 집합

-원-핫 인코딩(One-Hot Encoding) : 단어 집합의 크기를 벡터의 차원으로 하고, 표현하고 싶은 단어의 인덱스에 1을, 다른 인덱스에는 0을 부여하는 벡터 표현 방식

-과정: 정수 인코딩 수행 -> 표현하고 싶은 단어의 고유한 정수를 인덱스로 간주하여 해당 위치에 1을, 나머지 위치에 0을 부여

 

2. 케라스를 이용한 원-핫 인코딩

-케라스 Tokenizer로 정수 인코딩 수행

-text_to_sequences()로 이를 정수 시퀀스로 변환

-to_categorical()로 정수 인코딩된 결과로부터 원-핫 인코딩 수행

[2, 5, 1, 6, 3, 7]

[[0. 0. 1. 0. 0. 0. 0. 0.] # 인덱스 2의 원-핫 벡터

[0. 0. 0. 0. 0. 1. 0. 0.] # 인덱스 5의 원-핫 벡터

[0. 1. 0. 0. 0. 0. 0. 0.] # 인덱스 1의 원-핫 벡터

[0. 0. 0. 0. 0. 0. 1. 0.] # 인덱스 6의 원-핫 벡터

[0. 0. 0. 1. 0. 0. 0. 0.] # 인덱스 3의 원-핫 벡터

[0. 0. 0. 0. 0. 0. 0. 1.]] # 인덱스 7의 원-핫 벡터

 

3. 원-핫 인코딩의 한계

- 단어의 개수가 늘어날 수록, 벡터를 저장하기 위해 필요한 공간(=벡터의 차원)이 계속 늘어난다는 단점

- 단어의 유사도를 표현하지 못한다는 단점

-해결책 2가지

1) 카운트 기반의 벡터화 방법인 LSA(잠재 의미 분석), HAL 등

2) 예측 기반으로 벡터화하는 NNLM, RNNLM, Word2Vec, FastText 등

그 외 카운트 기반과 예측 기반 두 가지 방법을 모두 사용하는GloVe

# 02-09 데이터 분리

1. 지도 학습(Supervised Learning)

-훈련 데이터: X_train, y_train (문제지와 정답)

-테스트 데이터: X_test, y_test(시험지와 정답)

-훈련 데이터로 기계 학습 후 시험 데이터로 예측도 평가

 

2. X와 y 분리하기

-zip 함수로 분리하기

-데이터프레임으로 분리하기

-Numpy로 분리하기

 

3. 테스트 데이터 분리하기

- 사이킷런의 train_test_split() : 데이터의 순서를 섞고나서 훈련 데이터와 테스트 데이터를 분리

- X : 독립 변수 데이터
- y : 종속 변수 데이터
- test_size : 테스트용 데이터 개수(1보다 작을시 비율) 지정
- train_size : 학습용 데이터의 개수(1보다 작을시 비율) 지정
- random_state : 난수 시드

 

# 02-10 한국어 전처리 패키지

형태소와 문장 토크나이징 도구들인 KoNLPy와 KSS(Korean Sentence Splitter)와 함께 유용하게 사용할 수 있는 패키지들

1. PyKoSpacing

-띄어쓰기가 되어있지 않은 문장을 띄어쓰기를 한 문장으로 변환해주는 패키지

pip install git+https://github.com/haven-jeon/PyKoSpacing.git

 

GitHub - haven-jeon/PyKoSpacing: Automatic Korean word spacing with Python

Automatic Korean word spacing with Python . Contribute to haven-jeon/PyKoSpacing development by creating an account on GitHub.

github.com

 

2. Py-Hanspell

- 한글 맞춤법 검사기, 띄어쓰기 또한 보정함

pip install git+https://github.com/ssut/py-hanspell.git

 

GitHub - ssut/py-hanspell: 파이썬 한글 맞춤법 검사 라이브러리. (네이버 맞춤법 검사기 사용)

파이썬 한글 맞춤법 검사 라이브러리. (네이버 맞춤법 검사기 사용). Contribute to ssut/py-hanspell development by creating an account on GitHub.

github.com

 

3. SOYNLP

1) soynlp란?

- 품사 태깅, 단어 토큰화 등을 지원하는 단어 토크나이저

- 데이터에 자주 등장하는 단어들을 단어로 분석

2) 특징

- 기존의 형태소 분석기들은 신조어나 형태소 분석기에 등록되지 않은 단어 같은 경우에는 제대로 구분하지 못하는 단점

-> 특정 문자 시퀀스가 함께 자주 등장하는 빈도가 높고, 앞 뒤로 조사 또는 완전히 다른 단어가 등장하는 것을 고려해서 해당 문자 시퀀스를 형태소라고 판단하는 단어 토크나이저가 바로 soynlp

- 학습 기반의 단어 토크나이저이므로 기존의 KoNLPy에서 제공하는 형태소 분석기들과는 달리 학습 과정을 거쳐야 함

3) 내부구조

- 내부적으로 응집 확률(cohesion probability)브랜칭 엔트로피(branching entropy)를 활용한 단어 점수표로 동작

- WordExtractor.extract()로 전체 코퍼스에 대한 단어 점수표 계산

- 응집 확률 : 내부 문자열(substring)이 얼마나 응집하여 자주 등장하는지를 판단하는 척도

  Ex) '반포한강공원에'보다 '반포한강궁원'의 응집 확률이 높음

- 브랜칭 엔트로피 : 주어진 문자열에서 얼마나 다음 문자가 등장할 수 있는지를 판단하는 척도

         ㄴ하나의 완성된 단어에 가까워질수록 문맥으로 인해 점점 정확히 예측할 수 있게 되면서 점점 줄어드는 양상 보임

  Ex) '디스' 다음에는 다양한 문자가 올 수 있으니까 1.63이라는 값을 가지는 반면, '디스플'이라는 문자열 다음에는 다음 문자로 '레'가 오는 것이 너무나 명백하기 때문에 0이란 값 가짐

4) L tokenizer

- L 토큰 + R 토큰으로 나누되, 분리 기준으로 점수가 가장 높은 L 토큰을 찾아내는 원리

  Ex) 공원+에, 공부+하는

5) 최대 점수 토크나이저

- 띄어쓰기가 되지 않는 문장에서 점수가 높은 글자 시퀀스를 순차적으로 찾아내는 토크나이저

- MaxScoreTokenizer()

 

4. SOYNLP를 이용한 반복되는 문자 정제

- 의미없이 반복되는 것을 하나로 정규화시켜줌

  Ex) ㅋㅋ, ㅋㅋㅋ, ㅋㅋㅋㅋ -> ㅋㅋ

 

5. Customized KoNLPy

- 형태소 분석기에 사용자 사전을 추가하는 패키지

pip install customized_konlpy

- Twitter()에 add_dictionary('단어', '품사')와 같은 형식으로 사전 추가

twitter.add_dictionary('은경이', 'Noun')