slide-image

 

NLTK

# 02

 

이제 진짜 nltk로 넘어가려 한다. 

 

<nltk.와 관련된 함수들>

nltk.download() : GUI 로 관련된 데이터 다운로드

nltk.__file__ : nltk 설치 파일 위치

form nltk.book import * : book, sents, texts, words등이 import

text.concordance("단어") : 단어가 어떻게 text에서 사용되는지 모두 보여줌

test.dispersion_plot([리스트]) : 단어의 인덱스를 체크해 얼마나 분산되어 있는지 그래프로 보여줌

len(set(text))/len(text) : diversity, 얼마나 같은 단어 쓰는지.

f=FreqDist(text) : FreqDist 클래스 생성, f=FreqDist(len(w) for w in myList)로 나타낼 수도 있음

f.most_common(숫자) : 빈도수가 숫자보다 높은 것들을 가장 빈번한 순으로 [('단어', 횟수), ('단어', 횟수),,,] 형태로 저장됨

f.inc(sample) : 횟수를 높임

f['단어'] : 횟수를 반환

f.freq('단어') : 퍼센트(<1)로 나타냄

f.plot() : 그래프로 나타냄

 

<corpus>

nltk.corpus 모듈이 로드되면, set of corpus를 자동으로 생성한다.

코퍼스 format이 따로 있는데, 또한 corpus reader class도 따로 존재함.

corpus reader class에는 PlaintextCorpusReader, BracketParseCorpusReader가 있음.

nltk.corpus 모듈이 로드되면, set of corpus를 자동으로 생성한다.

각각의 corpus reader 들은 코퍼스로부터 읽는 데이터의 다양한 method를 제시함.

PlaintextCorpusReader는 raw, words, sents, paras를 제공한다.

 

<corpus 분류>

isolated: gutenberg, webtext, udhr

categorized: brown

overlapping: reuters

temporal: inaugural

 

<brown corpus 관련 함수>

브라운 코퍼스는 카테고리 별로 코퍼스를 나눠 놓았다. 

일단은 from nltk.corpus import brown을 한다.

b=brown.raw(혹은 words, sents, paras)('파일명') : 파일명(세부 코퍼스 파일)을 read한다.

b.fileids() : 리스트[]로 brown 세부 코퍼스 파일들을 가져옴

b.fileids(['카테고리명']) :  카테고리에 포함된 파일들을 리스트로 가져옴

b.categories() : 카테고리들을 모두 가져옴

b.categories([fileids]) : fileids의 카테고리들을 가져옴

b.raw()

b.raw(fileids=[f1,f2,f3..]) : f1, f2, f3의 파일들을 raw로 읽어들임

b.raw(categories=[c1,c2]) : 카테고리 c1, c2를 raw로 읽어들임

b.words()

b.words(categories=[c1,c2]) : 카테고리 c1, c2를 word로 읽어들임

sents()

sents(categories=[c1,c2]) : 카테고리 c1, c2를 sent로 읽어들임

open(fileid)

 

<brwon의 news 카페고리에 can, could, may 횟수 조사(stylistics)>

import nltk
from nltk.corpus import brown

news=borwn.words(categories='news')
fd=nltk.FreqDist(w.lower() for w in news)
m=['can', 'could', 'may']
for word in m:
    print(word, fd[word]) #f.['단어']는 f에서 단어의 횟수를 반환함.

<FreqDist Functions 메서드 정리>

위랑 중복될 수도 있음.

fdist=nltk.FreqDist(sample) : sample은 GNI.words()여도 되고, 아무거나 가능. FreqDist 클래스 생성

fdist['단어'] : 단어가 몇 번 나오는지 셈

fdist.keys() : 내림차순으로 정렬한 횟수의 리스트. 첫번째가 가장 많이 나온 sample임

fdist.freq('단어') : 단어의 비율(<1)을 나타냄

 

<Conditional Frequency Distribution, ConditionalFreqDist 메서드 정리>

g=['news', 'religion', 'SF'] #장르
w=['can', 'could', 'may'] #단어

cfd=nltk.ConditionalFreqDist(
    (g, w) #(condition, sample)의 튜플 형식
    for g in brown.categories()
    for w in brown.words(categories=g))
#클래스 생성

cfd=tabulate(conditions=g, samples=w) : 장르별로 단어가 몇 번 나오는지 테이블로 보여줌

cfd.conditions() : condition을 알파벳순으로 정렬한 리스트
cfd[condition][sample]

cfd[condition] : 이 조건에 대한 distribution 빈도

 

<nltk 코퍼스가 아닌 own coupus에 대해서>

PlaintextCorpusReader을 사용하거나 BracketParseCorpusReader을 사용한다.

이 둘은 모두 클래스임.

Plaintext로 불러올 때는 

from nltk.corpus import PlaintextCorpusReader
root='경로'
w=PlaintextCorpusReader(root, '.*') #디렉토리임
w.words('파일명')

이런 식으로 하면 되고,

BracketParse로 불러올 때는

from nltk.corpus import BracketParseCorpusReader
root=r'경로'
pattern=r".*/wsj_.*\.mrg"
p=BracketParseCorpusReader(root, pattern)

이렇게 하면 된다.

 

<GNI 논문 코퍼스 만들기(Own)>

from nltk.corpus import *
root='GNI 코퍼스 다운받은 경로(디렉터리)'
GNICorpus=PlaintextCorpusReader(root, '.*\.txt', encoding='utf-8')
GNICorpus.raws('파일이름') #txt파일

 

<현재 경로 보기>

import os

print(os.getcwd())

 

<Plaintext Corpara에서 제공하는 read 메서드>

raw, sents, words, paras가 있다.

raw는 전부를 큰 String으로 하는 것이며, words는 단어별 스트링을 리스트로 하는 것이다.

raw에서 문장단위로 나눌 때 nltk.sent_tokenize(스트링)를 이용한다.

GNISents=nltk.sent_tokenize(GNI.raw())

 

 


 

 

 

기말고사 범위

 

 

concordance 등은 Text 객체에서만 사용할 수 있는데, 이미 있는 코퍼스를 Text로 읽으면 된다. 

test=nltk.Text(cltk.corpus.gutenberg.word('코퍼스명.txt'))
test.concordance("surprize")

 

Reuters corpus는 test와 training set으로 분류되어 있다. 

브라운 코퍼스랑 다르게 overlap 되어 있어서 하나의 코퍼스가 여러 topics에 걸쳐 있을 수 있다. 

그래서 categories나 fileids, words에서도 리스트 인자를 받을 수 있다.

reuters.cotegories(['training/9865', 'training/9880']) #등이나
reuters.fileids(['barley', 'corn']) #등이나
reuters.words(['trainint/9865', 'training/9880']) #등이
reuters.words(categories=['barley', 'corn']) #가능

 

 

코퍼스를 다른 언어로 읽으려면, words()전에 언어를 쓰면 된다.

nltk.corpus.cess_esp.words()
nltk.corpus.floresta.words()
nltk.corpus.indian.words('hindi.pos')

그리고 udhr(세계인권선언문)은 언어별로 읽으려면 ,이런식으로 읽으면 된다.

nltk.corpus.udhr.fileids()
nltk.corpus.udhr.words('Javanese-Latin1')

따라서 여러나라로 코퍼스를 만든 세계인권선언문에서 각 나라 언어에서 word의 글자 길이를 누적(cumulative)한 것? 말이 좀 이상한데, 어쨌든 구현하면 이렇게 된다.

from nltk.corpus import udhr
languages=['Chickasaw', 'English', 'German_Deutsch', 'Greenlandic_Inuktikut', 'Hungarian_Magyar', 'Ibibio_Efik']
cfd=nltk.ConditionalFreqDIst(
    (lang, len(word))
    for lang in languages
    for word in udhr.words(lang+'-Latin1'))
    
cfd.plot(cumulative=True)

 

중간고사 때 했듯이, cfd는 pair로 되어야하는데, (condition, event)로 페어가 구성된다.

from nltk.corpus import brown
cfd=nltk.ConditionalFreqDist(
    (genre, word)
    for genre in brown.categories()
    for word in nltk.words(categories=genre))
    
>>>cfd(['news']).most_common(20)
>>>cfd(['romance']['could'])

이런 식으로 사용하는데, 마지막은 인터프리터 창에서 실행한 것을 나타냄(>>>)

어쨌든 저렇게 news 카테고리에서 가장 많이 사용되는 언어를 나타낼 수 있고, 결과도 pair로 나오는데, (word, 횟수)이런 식으로 나온다. 

그리고 두번 째는 로맨스 카테고리에서 could가 얼마나 나오는지를 나타낼 수 있다.

 

그치만 plot과 tabulate는 pair 인자로 conditions와 event가 아닌 samples와 conditions가 들어간다.

from nltk.corpus import inaugural
cfd=nltk.ConditionalFreqDist(
    (targer, fileid[:4])
    for fileid in inaugural.fileids()
    for w in inaugural.words(fileid)
    if w.lower().startswith(target)
    for target in ['america', 'citizen']
)
cfd.plot()

이렇게 되면, 그래프의 x축은 fileid가 되고, 그래프의 각 선들이 america, citizen을 나타낼 것이다.

 

from nltk.corpus import udhr
languages=['Chickasaw', 'English', 'German_Deutsch', 'Greenlandic_Inuktikut', 'Hungarian_Magyar', 'Ibibio_Efik']
cfd=nltk.ConditionalFreqDIst(
    (lang, len(word))
    for lang in languages
    for word in udhr.words(lang+'-Latin1'))
    
cfd.tabulate(conditions=['English', 'German_Deutsch'], samples=range(10), cumulative=True)

위와 같은데 이번에는 plot이 아닌 tabulate를 한 결과이다. 

이렇게 되면, 표가 만들어지는데, eng와 german_deutsch의 글자 길이 들이 누적되어서 표시될 것이다.

 

 

 

bigrame은 그냥 두 개씩 묵은 것인데, nltk함수에 내장되어 있다.

list(nltk.bigrams(sent))로 쓰면 된다.

안에가 문장이어야 한다는 것에 주의

 

def generate_model(cfdist, word, num=15):
    for i in range(num):
    	print(word, end=' ')
        word=cfdist[word].max()

text=nltk.corpus.genesis.words('english-kjv.txt')
bigrams=nltk.bigrams(text)
cfd=nltk.ConditionalFreqDist(bigrams)

>>>generate_model(cfd, 'living')

별 의미 없는 코드긴 하지만, living 뒤에 가장 많이 나오는 것(creature) 또 creature 뒤에 가장 많이 나오는 것(that), that 다음에 가장 많이 나오는 것(he) 이 15개 나온다. 여기 안에는 ,도 포함되어 나온다.

 

 

사실 , 이나 he, that 같은 경우는 제외하는 것이 더 의미있는 코드가 될 것인데, list로 제외해야할 것들을 nltk가 모아두었다.

nltk.corpus.stopwords이다.

from nltk.corpus import stopwords

def content_fraction(text):
    stopwords=nltk.corpus.stopwords.words('english')
    content=[w for w in text if w.lower() not in stopwords]
    return len(content)/len(text)

>>>content_fraction(nltk.corpus.reuters.words())
0.736어쩌고저쩌고

이런 식으로 사용함

 

 

FreqDist 객체는 서로 비율을 비교할 수 있다.

puzzle_letters=nltk.FreqDist('egivrvonl')
obligatory='r'
wordlist=nltk.corpus.words.words()

>>>[w for w in wordlist if len(w)>=6
                        and obligatory in w
                     	and nltk.FreqDist(w)<=puzzle_letters]

['glover', 'gorlin', 'govern', 'grovel', 'ignore', 'involver', 'lienor', 'linger', 'longer', 'lovering', 'noiler', 'overling', 'region', 'renvoi', 'revolving', 'ringle', 'roving', 'violer', 'virole']

egivrvonl이라는 뭔지도 모르겠는 단어의 FreqDist를 생성해주고, wordlist에 있는 단어들 중, 6글자 이상이고 r이 들어가며, egivrvonl보다 각 letter의 Frequency가 낮은 단어를 알려준다.

 

이름들의 끝 알파벳의 성별에 따른 분포를 파악하는 방법이다.

names=nltk.corpus.names
male_names=names.words('male.txt')
female_names=names.words('female.txt')

cfd=nltk.ConditionalFreqDist(
    (fileid, name[-1])
    for fileid in names.fileids()
    for name in names.words(fileid))
    
>>>cfd.plot()

그래프의 x축은 name[-1]일 것이고(이름들의 끝 알파벳), 각 선은 female.txt와 male.txt일 것이다.

왜냐하면, names 코퍼스에는 fileid가 female.txt와 male.txt밖에 없음..

 

 

 

코퍼ㅡ 중에 단어에 대한 발음이 나와있는 코퍼스가 있다.

nltk.corpus.cmudict인데, 불러올 때 entries()로 불러와야 한다.

entries=nltk.corpus.cmudict.entries()
for entry in entries[4321:4330]:
    print(entry)

 뭐 대충 이런 식이면 ('단어', ['발음1', '발음2', .....] 식의 pair으로 나온다.

따라서 P와 T로 끝나는 3글자 단어의 중간 발음을 알고 싶으면, 

for word, pron in entries:
    if len(pron)==3:
    	ph1, ph2, ph3=pron
        if ph1=='P' and ph3=='T':
        	print(word, ph2, end=' ')

이렇게 하면 된다.

 

그리고 각 단어에서 명사발음으로 끝나는 것들을 찾을 수 있다.

명사발음을 N, INO, K, S라고 하면,

syllable=['N', 'IHO', 'K', 'S']
>>>[word for word,pron in entries if pron[-4:]==syllable]

이런 식임.

 

 

(생략 : pron 뒷 부분, 언어 비교, toolbox)

 

wordnet은 동의어 등을 DB로 저장한 사전이다. 아마 영어만 있는 듯.

synsets(synonym set)이 있다.

lemma와 synsets을 헷갈리지 말기

 

from nltk.corpus import wordnet as wn
wn.synsets('motorcar') #[Synset('car.n.01')]
wn.synset('car.n.01').lemma_names() #['car', 'auto', 'automobile', 'machine', 'momtorcar']
wn.synset('car.n.01').definition() #'a motor vehicle with four wheels; usually~~'
wn.synset('car.n.01').examples() #['he needs a car to get to work']
wn.synset('car.n.01').lemmas() #[Lemma('car.n.01.car'), Lemma('car.n.01.auto'), Lemma('car.n.01.automobile') ....]

motorcar은 unambiguous하므로, synsets이 하나만 나옴.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

[ANN] #01  (0) 2019.05.05
[NLTK] #03  (0) 2019.05.04
[NLTK] #01  (0) 2019.04.08