2021. 8. 18. 22:33ㆍNLP
토픽모델링은 방대한 양의 텍스트 자료의 주요 주제를 머신러닝을 통해 추출하는 기법이다.
토픽모델링 기법 중에 하나인 잠재 디리클레 할당(Latent Dirichlet Allocation, LDA)을 사용할 것이다.
산림빅데이터거래소의 산림교육정보 프로그램교육목적 데이터를 활용할 것이다.
#한글 깨짐을 방지 #런타임을 빨리 하기 위해 코랩에서 이 코드를 돌리신 뒤, '런타임-런타임 다시 시작' 누르기 #다시 이 코드를 돌리기. (총 2번 돌리는 것) import matplotlib as mpl import matplotlib.pyplot as plt %config InlineBackend.figure_format = 'retina' !apt -qq -y install fonts-nanum import matplotlib.font_manager as fm fontpath = '/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf' font = fm.FontProperties(fname=fontpath, size=9) plt.rc('font', family='NanumBarunGothic') mpl.font_manager._rebuild()
#런타임을 재시작하신 뒤 위 셀의 코드를 다시 돌리면, 안깨짐. #만약 왼쪽 상단에 한글이 보이지 않으신다면, 한글깨짐이 있는 것이기 때문에 #런타임을 완전히 초기화 시키신 뒤 위 셀의 코드를 다시 실행 plt.figure(figsize=(5,5)) plt.plot([0,1],[0,1], label='한글테스트용') plt.legend()
데이터 분석하기
df= pd.read_csv('./프로그램운영목적.csv', encoding='cp949') df.head() df.shape
#파일의 첫행이 필요없는 행이라서 삭제 df1 = df.drop([0]) df1.head()
전처리 및 형태소 분석
형태소 분석은 언어에 있어서 최소 의미 단위이다.
#1차 전처리 import re import numpy as np def clean_str(text): if text == np.nan: return '' pattern = '([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)' # E-mail제거 text = re.sub(pattern=pattern, repl=' ', string=text) pattern = '(http|ftp|https)://(?:[-\w.]|(?:%[\da-fA-F]{2}))+' # URL제거 text = re.sub(pattern=pattern, repl=' ', string=text) pattern = '([ㄱ-ㅎㅏ-ㅣ]+)' # 한글 자음, 모음 제거 text = re.sub(pattern=pattern, repl=' ', string=text) pattern = '<[^>]*>' # HTML 태그 제거 text = re.sub(pattern=pattern, repl=' ', string=text) pattern = '[^\w\s]' # 특수기호제거 text = re.sub(pattern=pattern, repl=' ', string=text) pattern = '\n' #줄바꿈제거 text = re.sub(pattern=pattern, repl=' ', string=text) return text df1['text']=df1['프로그램 운영목적 내용'].apply(clean_str)
df1['text']
'text' 에 전처리한 데이터를 넣는다. 파일에서 '프로그램 운영목적 내용'의 데이터를 전처리한 후 'text'로 보여준다.
#형태소 분석을 위한 라이브러리 !pip3 install konlpy
#konlpy에서 '꼬꼬마'라는 형태소 분석기 사용 from konlpy.tag import Kkma kkma=Kkma()
형태소 분석기에 대한 설명 https://konlpy.org/ko/v0.5.2/
#형태소를 분석해줄 함수 #여기서 NN은 일반 명사를 뜻한다. def to_nouns(text): text_pos=kkma.pos(text) nouns=[] #if '코로나' in text: #nouns.append('코로나') #인식 못하는 중요한 키워드인 경우 입력 for a,b in text_pos: if len(a)>1: if'NN' in b: nouns.append(a) return nouns
NN으로 명사로 추출했다.
다른 품사는 참고해서 바꾸기
http://kkma.snu.ac.kr/documents/?doc=postag
#불용어,stopwords를 처리하는 코드 stopwords=['이','가', '은', '는']
불용어는 '은', '는', '이', '가' 와 같은 의미없는 단어와
분석상 관심이 없는 단어를 삭제한다.
#반복문이 어디까지 진행되었는지 표시해주는 함수 #형태소 분석 및 stopwords제거 진행율을 표시해줌 from tqdm import tqdm
#형태소 분석 및 stopwords를 제거 nountexts=[] for e in tqdm(df1['text']): temp_X=[] temp_X=to_nouns(e) temp_X=[e for e in temp_X if not e in stopwords] if len(temp_X)>0: nountexts.append(temp_X)
nountext 에 전처리한 데이터 넣어준다. (리스트 형태)
#분석된 단어들 중 동의어를 묶기 for outer_ndx, out in enumerate(nountexts): for inner_ndx, inner in enumerate(out): if inner=='학교': #바꿀 단어 nountexts[outer_ndx][inner_ndx]='대학' #유지할 단어 if inner=='대학교': nountexts[outer_ndx][inner_ndx]='대학' if inner=='기업': nountexts[outer_ndx][inner_ndx]='그룹' if inner=='양성': nountexts[outer_ndx][inner_ndx]='육성' if inner=='교원': nountexts[outer_ndx][inner_ndx]='교수' if inner=='교수님': nountexts[outer_ndx][inner_ndx]='교수' if inner=='교수진': nountexts[outer_ndx][inner_ndx]='교수' if inner=='공부': nountexts[outer_ndx][inner_ndx]='학업'
#지금 분석된 단어들은 각 행 별로 묶여있음. #nested list 형태 print(nountexts)
빈도분석
#전체적인 토픽을 보기 위해 nested list를 풀어준다 all_texts=[] for doc in nountexts: for e in doc: all_texts.append(e)
all_texts
#분석된 단어들의 순서를 준다. all_texts=pd.Series(all_texts)
#순서 매긴 단어들의 각 빈도 all_texts.value_counts()
#단어의 빈도 상위 10 all_texts.value_counts().head(10)
빈도를 추출한 결과
프로그램 71
운영 51
스트레스 49
활동 49
해소 45
이것을 표 데이터 프레임 형태로 엑셀에 저장한다.
#엑셀로 뽑기 위해 데이터프레임으로 전환 ncount=pd.DataFrame(all_texts.value_counts())
#엑셀 형태로 저장하기 ncount.to_excel('ncount.xlsx')
워드 클라우드 그리기
from wordcloud import WordCloud wc = WordCloud(font_path='/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf', background_color='white', width=1000, height=1000) cloud = wc.generate_from_frequencies(all_texts.value_counts().head(80)) #head(80)은 상위 80개 단어를 그린다는 의미 plt.figure(figsize=(10, 8)) plt.axis('off') plt.imshow(cloud) plt.show()
토픽모델링
#토픽모델링을 해주는 gensim 라이브러리 from gensim import corpora, models import gensim
#각 단어에 숫자로 id를 부여 dictionary=corpora.Dictionary(nountexts)
#그 단어에 대응하는 빈도를 연결 corpus=[dictionary.doc2bow(text) for text in nountexts]
각 단어에 숫자로 id 부여해 dictionary 변수 만든다.
단어에 빈도를 연결해 corpus 변수를 만든다.
LDA 모델을 사용할 것이다.
이 모델은 문서의 형태소를 분석하여 "특정 명사가 주요 키워드로 등장할 확률"을 구하고 이를 바탕으로 자주 같이 등장한 단어들을 묶어 '토픽'으로 설정한다.
#LDA 모델 #num_topics=10은 한 토픽 수를 10개 ldamodel=gensim.models.ldamodel.LdaModel(corpus, num_topics=10, id2word=dictionary)
# num_words=5는 한 토픽당 단어 수를 5개로 지정 ldamodel.print_topics(num_words=5)
(토픽의 수, 한 토픽 당 단어 수의 이상적인 수에 대해서 더 공부해야겠다!)
[(0, '0.049*"체험" + 0.047*"진로" + 0.035*"제공" + 0.030*"프로그램" + 0.018*"스트레스"'),
(1, '0.102*"프로그램" + 0.091*"운영" + 0.035*"다양" + 0.035*"스트레스" + 0.035*"자극"'),
(2, '0.071*"교육" + 0.071*"안전" + 0.048*"실시" + 0.040*"예방" + 0.040*"안전사고"'),
(3, '0.055*"이용" + 0.055*"목재" + 0.055*"향상" + 0.041*"해소" + 0.041*"스트레스"'),
(4, '0.039*"제공" + 0.039*"중요성" + 0.039*"나무" + 0.021*"프로그램" + 0.021*"교육"'),
(5, '0.076*"프로그램" + 0.074*"운영" + 0.040*"자연" + 0.040*"스트레스" + 0.040*"해소"'),
(6, '0.044*"기회" + 0.039*"스트레스" + 0.039*"제공" + 0.031*"해소" + 0.031*"다양"'),
(7, '0.057*"활동" + 0.038*"정서적" + 0.035*"제공" + 0.035*"안정" + 0.032*"증진"'),
(8, '0.053*"제공" + 0.044*"스트레스" + 0.044*"활용" + 0.039*"기회" + 0.039*"인자"'),
(9, '0.055*"프로그램" + 0.055*"운영" + 0.037*"체험" + 0.028*"해소" + 0.028*"기회"')]
#뽑힌 토픽들을 엑셀로 옮기기 topicn=ldamodel.print_topics(num_words=10)
topn=[] for doc in topicn: for e in doc: topn.append(e)
topn=pd.Series(topn)
topn=pd.DataFrame(topn)
topn.to_excel('tpn.xlsx')
토픽모델링
!pip install --upgrade pyLDAvis==2.1.2
import pyLDAvis import pyLDAvis.gensim as gensimvis pyLDAvis.enable_notebook()
lda_viz = gensimvis.prepare(ldamodel, corpus, dictionary)
#저장하기 pyLDAvis.save_html(lda_viz, './교육프로그램.html')
http://file:///C:/Users/%EA%B9%80%EC%A7%80%ED%9B%84/Downloads/%EA%B5%90%EC%9C%A1%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8.html#topic=0&lambda=1&term=
여기서 원은 각 토픽 1~10개 이다. 원의 크기는 그 토픽이 전체 텍스트에서 얼마나 높은 빈도로 나타나는지 보여준다. 원이 클수록 토픽의 비중이 크다. 원과 원 사이 거리는 해당 토픽이 얼마나 가까운지를 뜻한다. 즉 거리가 가까울수록 두 토픽이 한 문서 안에 자주 함께 등장하는 유사한 토픽임을 의미한다.
파란 막대 그래프는 전체 텍스트에서 빈도이고
빨강 막대 그래프는 선택된 토픽에서의 빈도를 의미한다.
이렇게 산림 교육 프로그램의 운영상세목적을 바탕으로 토픽을 분류해 어떤 주제가 있고 어떤 주제가 많은 지 알 수 있다.
'NLP' 카테고리의 다른 글
Fasttext 논문 리뷰 : Enriching Word Vectors with Subword Information (0) | 2022.01.22 |
---|---|
GloVe 논문 리뷰 : Global Vectors forWord Representation (0) | 2022.01.16 |
Skip-gram 코드 구현 : Word2Vec의 Skip-gram 모델 구현 (0) | 2022.01.10 |
CBOW 코드 구현 : Word2Vec의 CBOW 모델 구현 (0) | 2022.01.07 |
Word2Vec 논문 리뷰 : Efficient Estimation Of Word Representations In Vector Space (0) | 2022.01.03 |