- 어간과 형태소의 차이
- 형태소는 언어의 의미를 가진 최소 단위이며, 자립 형태소와 의존 형태소로 나뉩니다.
어간은 특정 단어에서 그 단어의 핵심 의미를 담은 부분으로, 주로 자립 형태소에 해당하지만, 어미와 같은 의존 형태소가 결합하여 문법적 기능이나 형태를 변화시킬 수 있습니다.
- 형태소는 의미를 구성하는 기본 단위로서의 역할을 하며, 어간은 특히 단어를 형성하고 변형 시키는 기반으로서의 역할을 합니다.
.를 기준으로 나눈다.)text_sample = """Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those!"""## 문장 단위 토큰화 import nltk sent_list = nltk.sent_tokenize(text_sample) print(type(sent_list), len(sent_list)) sent_list[:5]['Beautiful is better than ugly.',
'Explicit is better than implicit.',
'Simple is better than complex.',
'Complex is better than complicated.',
'Flat is better than nested.']
txt1 = "Many of life’s failures are people who didn't realize how close they were to success when they gave up."# 단어 단위 토큰화 word_list1 = nltk.word_tokenize(txt1) print(word_list1)['Many', 'of', 'life', '’', 's', 'failures', 'are', 'people', 'who', 'did', "n't", 'realize', 'how', 'close', 'they', 'were', 'to', 'success', 'when', 'they', 'gave', 'up', '.']
# 토큰 패턴을 지정해서 토큰화 regex_list1 = nltk.regexp_tokenize( txt1, #대상 문자열 r"\w+" # 토큰 패턴 정규표현식. \w: 일반글자, 숫자, `_` , +: 한글자 이상 ) regex_list1['Many',
'of',
'life',
's',
'failures',
'are',
'people',
'who',
'didn',
't',
'realize',
'how',
'close',
'they',
'were',
'to',
'success',
'when',
'they',
'gave',
'up']## Penn Treebank 토큰화 - word 단위 토큰화 #### 규칙1: 하이픈(-) 으로 구성된 것은 하나의 토큰으로 유지 "home-base" #### 규칙2: didn't 접어를 이용해서 축약한 경우는 분할 해준다. tokenizer = nltk.TreebankWordTokenizer() tb_list1 = tokenizer.tokenize(txt1) tb_list1['Many',
'of',
'life’s',
'failures',
'are',
'people',
'who',
'did',
"n't",
'realize',
'how',
'close',
'they',
'were',
'to',
'success',
'when',
'they',
'gave',
'up',
'.']
import nltk # nltk.download('stopwords') from nltk.corpus import stopwords # NLTK가 제공하는 stopword 언어 print(stopwords.fileids())['arabic', 'azerbaijani', 'basque', 'bengali', 'catalan', 'chinese', 'danish', 'dutch', 'english', 'finnish', 'french', 'german', 'greek', 'hebrew', 'hinglish', 'hungarian', 'indonesian', 'italian', 'kazakh', 'nepali', 'norwegian', 'portuguese', 'romanian', 'russian', 'slovene', 'spanish', 'swedish', 'tajik', 'turkish']
stopwords.words('english')['i',
'me',
'my',
'myself',
'we',
'our',
'ours',
'ourselves',
'you',
"you're",
"you've",
"you'll",
"you'd",
'your',
'yours',
'yourself',
'yourselves',
'he',
'him',
'his',
'himself',
'she',
"she's",
'her',
'hers',
...
"weren't",
'won',
"won't",
'wouldn',
"wouldn't"]
# 토큰화한 내용에 stopword 적용 [word for word in word_list1 if word.lower() not in stopwords.words('english')]['Many',
'life',
'’',
'failures',
'people',
"n't",
'realize',
'close',
'success',
'gave',
'.']
import nltk from nltk.corpus import stopwords def tokenize_text(text): """ 전체 문장들을 토큰화해 반환하는 함수 문장별로 단어 리스트(의미를 파악하는데 중요한 단어들)를 2차원 배열 형태로 반환 구두점/특수문자, 숫자, 불용어(stop words)들은 모두 제거한다. [매개변수] text: string - 변환하려는 전체문장 [반환값] 2차원 리스트. 1차원: 문장 리스트, 2차원: 문장내 토큰. """ #1. 받은 문장을 모두 소문자로 변환. text = text.lower() #2. 문장단위 토큰화 sent_tokens = nltk.sent_tokenize(text) #3. 클린징 작업 - 불용어, 특수문자, 숫자 등등을 제거 ## 불용어사전 loading stop_words = stopwords.words("english") stop_words.extend(['although', 'unless', 'may']) # 필요하다면 불용어 단어를 추가할 수있다. result_list = [] # 최종 결과를 저장할 리스트 for sent in sent_tokens: # 한문장씩 처리 result = nltk.regexp_tokenize(sent, r"[A-Za-z]+") # 불용어제거 result = [word for word in result if word not in stop_words] result_list.append(result) return result_list
result = tokenize_text(text_sample) result[:10][['beautiful', 'better', 'ugly'],
['explicit', 'better', 'implicit'],
['simple', 'better', 'complex'],
['complex', 'better', 'complicated'],
['flat', 'better', 'nested'],
['sparse', 'better', 'dense'],
['readability', 'counts'],
['special', 'cases', 'special', 'enough', 'break', 'rules'],
['practicality', 'beats', 'purity'],
['errors', 'never', 'pass', 'silently']]
stemmer객체.stem(단어)WordNetLemmatizer객체.lemmatize(단어 [, pos=품사])어간추출과 원형복원은 문법적 또는 의미적으로 변한 단어의 원형을 찾는 역할은 동일하다.
원형복원은 품사와 같은 문법적요소와 문장내에서의 의미적인 부분을 감안해 찾기 때문에 어간추출 방식보다 더 정교하다.
nltk.help.upenn_tagset('키워드') : 도움말pos_tag(단어_리스트) # Pos-tag 에서 반환한 품사표기(펜 트리뱅크 태그세트)을 WordNetLemmatizer의 품사표기로 변환 def get_wordnet_pos(pos_tag): """ 펜 트리뱅크 품사표기를 WordNetLemmatizer에서 사용하는 품사표기로 변환 형용사/동사/명사/부사 표기 변환 """ if pos_tag.startswith("J"): return wordnet.ADJ elif pos_tag.startswith("V"): return wordnet.VERB elif pos_tag.startswith("N"): return wordnet.NOUN elif pos_tag.startswith("R"): return wordnet.ADV else: return None
# 품사태깅 + 원형복원 words_tagging = [(word, get_wordnet_pos(pos)) for word, pos in pos_tag(words) \ if get_wordnet_pos(pos)!=None] words_tagging[('Working', 'v'),
('works', 'n'),
('worked', 'v'),
('Painting', 'n'),
('Painted', 'v'),
('paints', 'n'),
('Happy', 'a'),
('happier', 'a'),
('happiest', 'a'),
('am', 'v'),
('are', 'v'),
('is', 'v')]
# 원형 복원. lemm = WordNetLemmatizer() [lemm.lemmatize(word.lower(), pos=pos) for word, pos in words_tagging]['work',
'work',
'work',
'painting',
'paint',
'paint',
'happy',
'happy',
'happy',
'be',
'be',
'be']
###### 특정 품사만 추출 (명사만 추출) [word for word, pos in pos_tag(words) if pos.startswith('N')]['works', 'Painting', 'paints']
#### tokenize + cleaning 처리 함수 + 원형복원(stemming-어간추출) import nltk from nltk.corpus import stopwords, wordnet from nltk.tag import pos_tag from nltk.stem import WordNetLemmatizer def get_wordnet_pos(pos_tag): """ 펜 트리뱅크 품사표기를 WordNetLemmatizer에서 사용하는 품사표기로 변환 형용사/동사/명사/부사 표기 변환 """ if pos_tag.startswith("J"): return wordnet.ADJ elif pos_tag.startswith("V"): return wordnet.VERB elif pos_tag.startswith("N"): return wordnet.NOUN elif pos_tag.startswith("R"): return wordnet.ADV else: return None def tokenize_text2(text): """text 토큰화 처리 함수""" #1. 소문자 변환 text = text.lower() #2. 문장단위로 토큰화 sent_tokens = nltk.sent_tokenize(text) # [문장1, 문장2, 문장3, ..] ### 토큰화 + cleaning 작업 # 3. stopword들 loading stop_words = stopwords.words("english") # 필요하면 더 추가, 제거. # 4. lemmatizer 객체 생성 lemm = WordNetLemmatizer() # 최종 결과를 담을 리스트 result_tokens = [] # 문장별로 처리 for sent in sent_tokens: # regexp 토큰화 word_tokens = nltk.regexp_tokenize(sent, r"[a-zA-Z]+") #[단어1, 단어2, 단어3,.... ] #불용어 제거 word_tokens = [word for word in word_tokens if word not in stop_words] # 원형 복원 ## 품사부착 word_tokens = pos_tag(word_tokens) #[ (단어1, 품사), (단어2, 품사), ....] ## lemmatizer에서 사용하는 품사 string으로 변환. "NN" -> "n" word_tokens = [(word, get_wordnet_pos(pos)) \ for word, pos in word_tokens \ if get_wordnet_pos(pos) is not None] ## 원형복원 word_tokens = [lemm.lemmatize(word, pos=pos) for word, pos in word_tokens] result_tokens.append(word_tokens) return result_tokens
result = tokenize_text2(text_sample) result[:5][['beautiful', 'good', 'ugly'],
['explicit', 'well', 'implicit'],
['simple', 'well', 'complex'],
['complex', 'well', 'complicate'],
['flat', 'well', 'nest']]
with open("data/news.txt", encoding='UTF-8') as f: news_txt = f.read() # 토큰화 news_tokens = tokenize_text2(news_txt) news_tokens[:5][['sit', 'parent', 'hair', 'salon', 'min', 'kyu', 'bury', 'computer', 'game'],
['wear',
'gray',
'soccer',
'kit',
'boot',
'constantly',
'click',
'tile',
'floor',
'year',
'old',
'lose',
'parallel',
'universe',
'far',
'distract',
'noise',
'electric',
'clipper',
'faint',
'smell',
'hairspray'],
['seem',
'happen',
...
'tottenham',
'football',
'star',
'national',
'hero']]
# 2차원(중첩) 리스트 -> 1차원 news_words = [] for lst in news_tokens: news_words += lst news_words[:10]['sit',
'parent',
'hair',
'salon',
'min',
'kyu',
'bury',
'computer',
'game',
'wear']
# Text 클래스 객체 생성 -> 토큰 리스트를 전달 from nltk import Text import matplotlib.pyplot as plt news_text = Text(news_words, name="손흥민 뉴스") news_text<Text: 손흥민 뉴스>
# 토큰 조회 print(news_text[0]) print(news_text[ : 10])sit
['sit', 'parent', 'hair', 'salon', 'min', 'kyu', 'bury', 'computer', 'game', 'wear']
# 특정 토큰의 빈도수 news_text.count("son")45
plt.figure(figsize=(10,4)) plt.title("word freq") news_text.plot(20) # 빈도수가 큰 상위 20개 단어에 대해 선그래프를 작성 plt.show()
## 특정 단어가 문서의 어느부분들에 나오는지 시각화 plt.figure(figsize=(10, 10)) news_text.dispersion_plot( ['son', 'korean', "new", 'say', 'malden', 'football'] );
from nltk import FreqDist # Text객체를 이용해서 생성 fd = news_text.vocab() # 토큰 리스트 fd2 = FreqDist(news_words) # 문서 string fd3 = FreqDist(news_txt) # 글자단위 토큰화. print(fd) fd.pprint() fd3.pprint()<FreqDist with 560 samples and 1197 outcomes>
FreqDist({'son': 45, 'korean': 33, 'new': 17, 'say': 15, 'malden': 13, 'football': 13, 'south': 12, 'work': 12, 'success': 11, 'think': 11, ...})
FreqDist({' ': 2241, 'e': 1172, 'a': 859, 't': 857, 'o': 849, 'n': 732, 'i': 674, 's': 655, 'r': 587, 'h': 547, ...})
print("총 토큰수:", fd.N()) print("고유 토큰의 개수:", fd.B()) word = "new" print(f"{word}의 빈도수: {fd.get(word)}") print(f"{word}의 비율: {fd.freq(word)}")총 토큰수: 1197
고유 토큰의 개수: 560
new의 빈도수: 17
new의 비율: 0.014202172096908938
# 빈도수 순위 fd.most_common(10) # 상위 N개. 개수 생략-> 전체[('son', 45),
('korean', 33),
('new', 17),
('say', 15),
('malden', 13),
('football', 13),
('south', 12),
('work', 12),
('success', 11),
('think', 11)]
pip install wordcloudimport matplotlib.pyplot as plt from wordcloud import WordCloud # WordCloud 객체 생성 -> 어떻게 그릴지 설정. wc = WordCloud( max_words=50, # 최대 몇개 단어를 사용할지 설정. prefer_horizontal=0.5, # 가로쓰기 비율(기본: 0.9) width=500, height=500, relative_scaling=0.5, # 빈도수가 증가할 때 글씨 크기를 얼마나 크게할지 비율. #1: 빈도수와 폰트크기를 같은 비율로 확대. (빈도수가 두배면 폰트 크기도 두배.) min_font_size=1, max_font_size=30, background_color="white" ) # generate_from_frequencies({"단어":빈도, ...}) word_cloud = wc.generate_from_frequencies(fd) # 파일로 저장 word_cloud.to_file("news_wordcloud.png") plt.imshow(word_cloud) plt.xticks([]) plt.yticks([]) plt.show()