slide-image

 

NLTK

# 03

 

3장에서는 lemmatization, stemming, POS tagging, Parsing, SEntece breaking, Word segmentation을 배웠다.

 

lemmatization은 그 단어가 문장에서 어떻게 쓰였는지 알아내는 것이다.

 

HTML에서 코퍼스를 구축할 때,

html=urlopen(url).read()

raw=nltk.clean_html(html)

을 하면 ASCII로 바뀌고, 이걸 text로 바꾸기 위해서

tokens=nltk.wordpunct_tokenize(Raw)

text=nltk.Text(token)

를 하면 Text로 바꿀 수 있다.

 

url으로 string을 다운받으려면

from urllibk import *

response=request.urlopen(url)

raw=response.read()decode('utf8')

을 하면 된다.

 

string 클래스가 되었으니까 find, rfind 함수를 쓸 수 있고

url 전체를 가져왔으니 header와 footer을 떼어야 한다.

html 태그를 제거하기 위해서 raw=BeautifulSoup(html, 'html.parser').get_text()

from bs4 import BeautifulSoup을 해줘야한다.

BeautifulSoup은 unicode와 utf-8로 바꿀 때 쓰는 모듈이다.

 

tokenization을 하기위해서는

tokens=nltk.word_tokenize(raw)

을 쓰면되는데, list로 리턴한다.

token을 text로 변환하기 위해서는 

text=nltk.Text(tokens)를 쓰면 된다.

따라서 nltk.의 Text함수의 인자로는 list가 들어가야 한다.

리턴값은 nltk.text.Text 클래스가 생성된다.

 

nltk.text.Text 클래스에서는 여러가지 메소드를 사용할 수 있는데, 

concordance, collocation 등을 사용할 수 있다.

 

(RSS Feeds, feedparser)...?

 

os 패키지에는 getcwd()메소드와 listdir(경로), chdir(경로) 등이 있다.

 

스트링 중간에 끊어서 작성하는 방법은 

\하고 그냥 넘어가거나

(괄호로

묶어서 하거나)

"""로 묶을 수 있다.

 

 local encoding 을 하려면 맨 처음에 #-*- coding: utf-8 -*-으로 하면 된다.

 

문법에 관한 참스키 계층은

이렇게 되는데, 정규표현식에 대해서는 내용이 너무 많으므로 간략하게 설명하려고 한다.

 

^ : 이 패턴으로 시작

$ 이 패턴으로 종료

[] : 이 중에 하나

[^] : 피해야할 문자들 집합

| : 두 패턴 중 하나이어야 함

? : 0개거나 1개

+ : 하나 이상

* : 0개 이상

패턴{n} : n 번 반복

{n, m} : n번이상 최대 m 번 이하

\d : 숫자0-9

\w : 문자

\s : 화이트 스페이스 [\t\n\r\f]

. : wildcard. \n을 제외한 모든 문자

 

전화번호 4653으로 만들 수 있는 영어단어를 코딩해보면,

import re
wordlist=[w for w in nltk.corpus.words.words('en') if w.islower()]
[w for w in wordlist if re.search('^[ghi][mno][jlk][def]$', w)]

 

re모듈의 메소드에는

search : string 전체를 검색해 일치하는 첫번째 문자열을 찾는다.

match : string의 첫 문자열만을 비교하여 확인한다. 처음부터 일치하여야 함.

findall : 가장 많이 쓰이는 메소드로, 일치하는 것을 모두 찾아서 list로 반환한다.

sub : string 전체에서 일치하는 모든 것을 replace로 교체하고 str으로 반환한다. 

split : 주어진 스트링을 패턴으로 분리시킨다. re.split()을 사용해서 정규 표현식을 이용할 수 있다.

compile : 해당 정규 표현식을 re.RegexObject 객체로 저장할 수 있어 다시 쓰는 번거로움을 피할 수 있다.

 

*와 +는 greedy이므로 가장 긴 것을 가져온다.

가져올 때 non-greedy로 하려면 뒤에 ?를 붙이면 된다.

findall메소드에서 3번째 인자를 줄 수도 있는데 MULTILINE이 이에 해당된다.

 

GNI 논문의 이메일 주소를 출력해주는 코드를 써보면,

GNI=PlaintextCorpusReader("경로", ".*\.txt", encoding='utf-8')
giRaw=GNI.raw('파일이름.txt')
re.findall(r'[\w._%+=]+@[\w.-]+\.[a-zA-Z]{2,4}',giRaw)

 이렇게 된다.

 

(?!pattern) : Positive Lookahead, a(?=b)이면 a나 abc를 찾는다. consuming은 아님.

(?:pattern) : Negative Lookahead, a(?!b)은 a나 acc를 찾는다.

(?=pattern) : Non-Capturing Group, 캡처를 하지 않는다.

 

nltk에서 제공하는 findall의 정규표현식은 다르게 생겼다. 토큰 바운더리(<.>)로 표현한다.

 

lower()메서드를 통해서 텍스트를 normalized할 수 있다.

nltk의 stemmers에는 Porter와 Lancaster 가 있다.

[nltk.PorterStemmers().stem(t) for t in tokens] 등으로 할 수 있는데, 둘의 규칙이 다르다.

 

nltk의 lemmatizer는 affixes를 제거해서 사전에 있는 것만 반환한다.

from nltk.stem.wordnet import WordNetLemmatizer

[nltk.WordNetLemmatizer().lemmatize(t) for t in tokens]으로 쓸 수 있다.

(알아두기!)

 

lemmatisation은 사전을 기반으로, stemming이랑 구별. stem은 context안 보므로, lemmatisation이 더 정확도가 높음. 

in a 들을 제외하려면, [x for x in words if not (x in stopwords.words('english'))]하기

 

의미있는 단어들만을 통계에 넣기 위해서 평범한 단어를 제거하려면

from nltk.corpus import stopwords

words=[리스트]

[x for x in words if not(x in stopwords.words('english'))]

를 하기.

 

그래서 각 GNI 논문 별로 빈도수 많은 단어를 평범한 단어 제거후에 출력하는 코드는

GenomInfoCorpus=PaintextCorpusReader(corpus_root, '.*\.txt', encoding='utf-8')
giRaw=GenomInfoCorpus.raw()
giWords=GenomInfoCorpus.words()

from nltk. corpus import stopwords wnl=nltk.WordNetLemmatizer()

giRaws={}

for fileid in GenomInfoCorpus.fileids():
    giRaws[fileid]=GenomInfoCorpus.raw(fileid)
    giRaws[fileid]=re.sub(r'[\n\r.,()]', '', giRaws[fileid])
    words=nltk.word_tokenize(giRaws[fileid])
    words=[x for x in words if not (x.lower() in stopwords.words('english'))]
    fd=nltk.FreqDist(words)
    fd=sorted([(freq, word) for (word, freq) in fd.items()], revers=True)
   

​이렇게 된다.

 

nltk.regexp_tokenize()도 따로 있는데, 기본 tokenize보다 못하다. custom할 수 있다 정도만 알아두기.​

nltk.sent_tokenize(text) 메서드는 punctuation기준으로 sent를 나누기 때문에 문장 단위로 나누는 것이지만 정확도가 매우 떨어진다.

 

giWords=GNI.words('파일명')

giWord2=re.split(r'[\n\t]+', giRaw)

와 차이가 나는 이유는 첫번쨰 words는 ,나 :, ;들이 포함되기 때문이다.

 

string을 format 처리하면

'{} flies like an {}'.format('Time', 'arrow')

라고 하면 'Time flies like and arrow'로 나온다.

'{1} flies like an {0}'.format('Time', 'arrow')

은 'arrow flies like an Time'

'{:10} flies'.format('Time')

은 'Time          flies'가 된다.

'{:<10} flies'.format('Time')도 똑같음.

'{:>10} flies'.format('Time')은

'          Time flies'로 나온다.

 

import math

'{:4f}'.format(math.pi)은 3.141593으로 나오고,

'{:.4f}'.format(math.pi)은 3.1416으로 나온다.

 

'etc > NLTK' 카테고리의 다른 글

[ANN] #01  (0) 2019.05.05
[NLTK] #02  (0) 2019.04.09
[NLTK] #01  (0) 2019.04.08