자연어 처리3

Ho Jin Lee·2021년 9월 16일
0

자연어

목록 보기
3/3

불용어(Stopword)

큰 의미가 없는 단어 토큰. 자주 등장 하지만, 분석을 하는 것에 있어서는 큰 도움이 되지 않는 단어들.

I,my,me,over,조사(이/가),접미사(-님,-질)

NLTK에서 불용어 확인하기

from nltk.corpus import stopwords  
stopwords.words('english')[:10]  
#['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', 'your']  

NLTK를 통해 불용어 제거하기

from nltk.corpus import stopwords 
from nltk.tokenize import word_tokenize 

example = "Family is not an important thing. It's everything."
stop_words = set(stopwords.words('english')) 

word_tokens = word_tokenize(example)

result = []
for w in word_tokens: 
    if w not in stop_words: 
        result.append(w) 

print(word_tokens)
#['Family', 'is', 'not', 'an', 'important', 'thing', '.', 'It', "'s", 'everything', '.']
print(result) 
#['Family', 'important', 'thing', '.', 'It', "'s", 'everything', '.']

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

from nltk.corpus import stopwords 
from nltk.tokenize import word_tokenize 

example = "고기를 아무렇게나 구우려고 하면 안 돼. 고기라고 다 같은 게 아니거든. 예컨대 삼겹살을 구울 때는 중요한 게 있지."
stop_words = "아무거나 아무렇게나 어찌하든지 같다 비슷하다 예컨대 이럴정도로 하면 아니거든"
# 위의 불용어는 명사가 아닌 단어 중에서 저자가 **임의**로 선정한 것으로 실제 의미있는 선정 기준이 아님
stop_words=stop_words.split(' ')
word_tokens = word_tokenize(example)

result = [] 
for w in word_tokens: 
    if w not in stop_words: 
        result.append(w) 
# 위의 4줄은 아래의 한 줄로 대체 가능
# result=[word for word in word_tokens if not word in stop_words]

print(word_tokens) 
print(result)

아래의 링크는 보편적으로 선택할 수 있는 한국어 불용어 리스트를 보여줍니다. (여전히 절대적인 기준은 아닙니다.)
링크 : https://www.ranks.nl/stopwords/korean

한국어 불용어를 제거하는 더 좋은 방법은 코드 내에서 직접 정의하지 않고 txt 파일이나 csv 파일로 수많은 불용어를 정리해놓고, 이를 불러와서 사용하는 방법입니다.

정규 표현식(Regular Expression)


특정한 규칙을 가진 문자열의 집합을 표현하는 형식
1)정규 표현식 문법

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

3)문법 예시


.

import re
r=re.compile("a.c")
r.search("kkk") # 아무런 결과도 출력되지 않는다.
r.search("abc")
#<_sre.SRE_Match object; span=(0, 3), match='abc'>  
#a.c 라는 패턴이 존재하는지 찾는 것. 있다면 span=(시작,끝)으로 표현

?

import re
r=re.compile("ab?c")
r.search("abbc") # 아무런 결과도 출력되지 않는다.
r.search("abc")
#<_sre.SRE_Match object; span=(0, 3), match='abc'>  
r.search("ac")
#<_sre.SRE_Match object; span=(0, 2), match='ac'>  
#ab?c는 b가 존재할 수도 있고 안할 수도 있는 패턴, 즉 abc or ac를 의미한다.

*

import re
r=re.compile("ab*c")
r.search("a") # 아무런 결과도 출력되지 않는다.
#*은 바로앞의 문자가 0개 이상일때를 말한다. 존재하지 않을 수도, 아주많을 수도 있다. ac,abc,abbc,ab....bc의 경우를 말한다.
r.search("abbbbc") 
#<_sre.SRE_Match object; span=(0, 6), match='abbbbc'> 

+

import re
r=re.compile("ab+c")
r.search("ac") # 아무런 결과도 출력되지 않는다.
#+는 앞의 문자가 1개 이상을 말한다. *와 동일, 하지만 앞문자가 존재는 해야한다. abc,abbc,ab.....bc의 경우를 말함
r.search("abbbbc") 
#<_sre.SRE_Match object; span=(0, 6), match='abbbbc'>  

^

import re
r=re.compile("^a")
r.search("bbc") # 아무런 결과도 출력되지 않는다.
#^는 시작되는 글자를 지정. ^a는 a로 시작하는 글자를 말함.
r.search("ab")
#<_sre.SRE_Match object; span=(0, 1), match='a'>  

{숫자}

import re
r=re.compile("ab{2}c")
r.search("ac") # 아무런 결과도 출력되지 않는다.
r.search("abc") # 아무런 결과도 출력되지 않는다.
#숫자 만큼 앞의 문자가 반복된 경우를 말한다. 
ab{2}c의 경우 b가 두번 반복되어 abbc의 경우를 말한다.
r.search("abbc")
#<_sre.SRE_Match object; span=(0, 4), match='abbc'>

{숫자1, 숫자2}

import re
r=re.compile("ab{2,8}c")
r.search("ac") # 아무런 결과도 출력되지 않는다.
r.search("abc") # 아무런 결과도 출력되지 않는다.r=re
#앞에 문자가 숫자1이상 숫자2이하 개수가 있는 경우를 말함
#+ab{2,8}c는 b가 a와 c 사이에 2개이상, 8개이하 존재하는 경우.

{숫자,}

import re
r=re.compile("a{2,}bc")
r.search("bc") # 아무런 결과도 출력되지 않는다.
r.search("aa") # 아무런 결과도 출력되지 않는다.
#앞의 문자가 숫자 이상 반복되는 경우를 말함
#a{2,}bc => aabc, aaabc, a.....abc
r.search("aaaaaaaabc")
<_sre.SRE_Match object; span=(0, 10), match='aaaaaaaabc'> 

[]

import re
r=re.compile("[abc]") # [abc]는 [a-c]와 같다.
r.search("zzz") # 아무런 결과도 출력되지 않는다.
#[]안의 문자들중 "한개"의 문자를 가진 경우를 말함.[a-z]소문자[A-Z]대문자[0-9]숫자로 범위 설정가능 처음 만난 한 문자에 대해서만 span 출력.
r.search("a")
<_sre.SRE_Match object; span=(0, 1), match='a'> 
r.search("aaaaaaa")                                                                                               
<_sre.SRE_Match object; span=(0, 1), match='a'> 
r.search("baac")      
<_sre.SRE_Match object; span=(0, 1), match='b'>

[^문자]

^기호 뒤의 문자들을 제외한 모든 문자의 경우를 말함.
[^a-zA-Z] 영어 대소문자 제외

import re
r=re.compile("[^abc]")
r.search("a") # 아무런 결과도 출력되지 않는다.
r.search("ab") # 아무런 결과도 출력되지 않는다.
r.search("b") # 아무런 결과도 출력되지 않는다.
r.search("d")
#<_sre.SRE_Match object; span=(0, 1), match='d'> 

3)모듈 함수 예시


re.match()&re.search()

re.match는 첫 부분부터 정규 표현식과 확인
re.search는 정규 표현식 전체에 대해서 문자열 매치 확인

import re
r=re.compile("ab.")
r.search("kkkabc")  
<_sre.SRE_Match object; span=(3, 6), match='abc'>   
r.match("kkkabc")  #아무런 결과도 출력되지 않는다.
#ab. 으로 시작하지 않음으로 match결과는 나오지 않는다.
r.match("abckkk")  
#<_sre.SRE_Match object; span=(0, 3), match='abc'>  

re.split()

정규 표현식 기준으로 문자열을 분리하여 리스트로 리턴한다.

import re
text="사과 딸기 수박 메론 바나나"
re.split(" ",text)
#['사과', '딸기', '수박', '메론', '바나나']  

공백을 기준으로 분리가능.

re.findall()

정규 표현식과 매치되는 모든 문자열들을 리스트로 리턴. 없으면 빈 리스트.

import re
text="""이름 : 김철수
전화번호 : 010 - 1234 - 1234
나이 : 30
성별 : 남"""  
re.findall("\d+",text)
#['010', '1234', '1234', '30']

re.sub()

정규 표현식 패턴과 일치하는 문자열을 대체

import re
text="Regular expression : A regular expression, regex or regexp[1] (sometimes called a rational expression)[2][3] is, in theoretical computer science and formal language theory, a sequence of characters that define a search pattern."
re.sub('[^a-zA-Z]',' ',text)
#'Regular expression   A regular expression  regex or regexp     sometimes called a rational expression        is  in theoretical computer science and formal language theory  a sequence of characters that define a search pattern '  

4. 예제

import re  

text = """100 John    PROF
101 James   STUD
102 Mac   STUD"""  

re.split('\s+', text)  
#['100', 'John', 'PROF', '101', 'James', 'STUD', '102', 'Mac', 'STUD']
re.findall('\d+',text)  
#['100', '101', '102]
re.findall('[A-Z]',text)
#['J', 'P', 'R', 'O', 'F', 'J', 'S', 'T', 'U', 'D', 'M', 'S', 'T', 'U', 'D']
re.findall('[A-Z]{4}',text)  
#['PROF', 'STUD', 'STUD']
re.findall('[A-Z][a-z]+',text)
#['John', 'James', 'Mac'] 

5. 토큰화

NLTK에서는 Regexp Tokenizer를 사용하여 토큰화 가능.

import nltk
from nltk.tokenize import RegexpTokenizer
tokenizer=RegexpTokenizer("[\w]+")
print(tokenizer.tokenize("Don't be fooled by the dark sounding name, Mr. Jone's Orphanage is as cheery as cheery goes for a pastry shop"))
#['Don', 't', 'be', 'fooled', 'by', 'the', 'dark', 'sounding', 'name', 'Mr', 'Jone', 's', 'Orphanage', 'is', 'as', 'cheery', 'as', 'cheery', 'goes', 'for', 'a', 'pastry', 'shop'] 
#\w, 즉 문자나 숫자가 1개 이상있는 경우를 사용하여 토큰으로 만듬.

import nltk
from nltk.tokenize import RegexpTokenizer
tokenizer=RegexpTokenizer("[\s]+", gaps=True)
print(tokenizer.tokenize("Don't be fooled by the dark sounding name, Mr. Jone's Orphanage is as cheery as cheery goes for a pastry shop"))
#["Don't", 'be', 'fooled', 'by', 'the', 'dark', 'sounding', 'name,', 'Mr.', "Jone's", 'Orphanage', 'is', 'as', 'cheery', 'as', 'cheery', 'goes', 'for', 'a', 'pastry', 'shop']

#gaps=True로 토큰을 나누는 기준을 [\s], 공백으로 지정  하게 됨.
profile
배 터져 죽을 때까지

0개의 댓글