기술자료

DBMS, DB 구축 절차, 빅데이터 기술 칼럼, 사례연구 및 세미나 자료를 소개합니다.

기계 학습의 A to Z : 기계 학습을 활용한 연설문 분류

기술자료
DBMS별 분류
Etc
작성자
dataonair
작성일
2015-10-07 00:00
조회
4739


◎ 연재기사 ◎


기계 학습의 A to Z : scikit-learn을 활용한 기계 학습(모델 평가)


기계 학습의 A to Z : scikit-learn을 활용한 기계 학습 (차원 축소)


기계 학습의 A to Z : scikit-learn을 활용한 기계 학습 (군집화, Clustering)


기계 학습의 A to Z : IPython notebook과 scikit-learn을 활용한 기계 학습


기계 학습의 A to Z : scikit-learn을 활용한 기계 학습(문서 분류)


기계 학습의 A to Z : 인구 변화 시각화와 예측


기계 학습의 A to Z : 줄리아(Julia)와 기계 학습(1)


기계 학습의 A to Z : 기계 학습을 활용한 연설문 분류



기계 학습의 A to Z

기계 학습을 활용한 연설문 분류



정치인의 연설문은 중요한 의미를 담고 있다. 특히, 한 국가의 대통령 연설문은 전반적인 국정의 방향성과 현시점의 겹겹이 쌓인 문제에 대한 대처 방안을 제시하기 때문에 더욱 더 중요하다. 한편, 정치에 대한 기대치는 높지만 거듭되는 그의 대한 실망감으로 정치에 대한 피로감이 높아지고 있으며, 이로 인해 정치 무관심이 팽배하다. 정말 정치인의 말은 다 같을까 이 글에서는 전현직 대통령의 연설문에서 주제어를 찾고, 이 주제어를 기반으로 각 연설문이 대통령별로 군집화(구별)되는지 살펴본다.



문서를 분류, 군집하는 기술은 요즘과 같이 도서나 웹페이지가 하루에도 무수히 출판되는 상황에서 반드시 필요하다. 1990년대 구글이 등장하기 전, 최상위 포식자였던 야후에서 사용했던 분류와 군집의 기술은 인력이였다. 사람이 수많은 웹페이지를 보면서 정치, 사회, 과학등으로 문서를 분류했다. 결과는 비교적 정확하지만 많은 웹페이지를 처리하지 못하는 한계가 있었다. 기계 학습으로 문서를 분류하는 기술은 현재의 구글을 있을 수 있게 하였다고 하여도 과언이 아니다. 이 기술을 바탕으로 전현직 대통령의 연설문을 분류한다.

사용 도구는 파이썬 기계 학습 라이브러리인 scikit learn, pandas이다.



현재 대통령 연설문 단어 빈도

대통령의 취임 초기 연설문은 앞으로의 국정 운영에 가장 기본적인 지시계이기 때문에 그 의미가 크다. 박근혜 대통령의 2013년, 2014년 몇 개의 연설문에 자주 등장하는 단어를 알아보도록 한다. 전체적인 과정은 다음과 같다.



<리스트 1> 연설문에서 단어 빈도를 구하는 과정- 3개의 연설문에서 형태소 분석을 통해 명사만 추출한다
- 명사 빈도를 구한다
- 각 연설문의 명사 빈도를 모두 더한다



연설문은 청와대 홈페이지에서 구할 수 있다. 다음 주소( http://www1.president.go.kr/president/speech.php)에서 구한다. 구한 연설문을 형태소 분석하여 명사만을 추출해야 하는데 인터넷상에 다양한 형태소 분석기를 있으니 이를 통해 명사만을 구할 수 있다. 이 과정을 생략하고 싶다면 다음과 같은 명사만을 구한 문서를 사용한다. 다음은 연설문에서 명사만을 추출한 결과다.(<리스트 2> 참조)



<리스트 2> 한 연설문에서 구한 명사존경 국민 여러분
저 올해 초 신년 구상 우리 경제 혁신 재도약 위해 ‘경제혁신 3개년 계획’ 추진 바
세계 경제 글로벌 금융 위기 여파에서여전히 채 대전환 기
세계 각국 구조 개혁 강화 경쟁력 노력 통상 주도권 경쟁 치열 해
우리나라 예외
도약 정체냐 중대 한 기로
우리 경제 세계 10 위 기존 추격 형 전략 한계 직면 비정상 적 관행 들 경제 효율성 역동성 저하
수출 내수 대기업 중소기업 제조업 서비스업 간 불균형 등 해결 구조 적 과제 들
산적 해 인구고령화 OECD 국 중 속도 진행 2017 년 생산가능 인구 감소



<리스트 3>과 같이 단어의 빈도를 구하는 함수를 정의한다.



<리스트 3> 각 연설의 단어 빈도를 구하는 함수def file2df(filename):
with open(get_fullpath(filename), 'r') as f:
rawdata = f.read() data = rawdata.split('\n')
countvector = CountVectorizer(min_df=1)
words = countvector.fit_transform(data).toarray()
features = np.array(countvector.get_feature_names())
np.clip(words, 0, 1, out=words)
dist = np.sum(words, axis=0)
return pd.DataFrame(zip(features, dist), columns=['term', 'count'])



이 함수에 파일 이름을 입력하면 단어와 단어 빈도를 포함한 pandas의 데이터프레임을 반환한다. numpy의 clip, sum 함수로 빈도를 구했다. 이번에는 각 연설의 단어 빈도를 다 더하는 함수를 작성한다.



<리스트 4> 각 연설문에서 출현한 모든 단어 빈도를 구하는 함수def merge_all():
speech_park1 = file2df('park1_noun.txt')
speech_park2 = file2df('park2_noun.txt')
speech_park3 = file2df('park3_noun.txt')
speeches = pd.merge(speech_park1, speech_park2, on='term',
how='outer',
suffixes=('_park1', '_park2')).fillna(0) speeches = pd.merge(speeches, speech_park3, on='term',
how='outer').fillna(0)
speeches.rename(columns={'count':'count_park3'}, inplace=True) speeches['total'] = speeches['count_park1'] + speeches['count_park2'] + speeches['count_park3']
speeches = speeches.sort([('total')], ascending=True)
for row in speeches.itertuples():
print "['%s', %d, %d, %d, %d]," % (row[1], row[2], row[3], row[4], row[5])



각 연설문에서 단어 빈도 데이터프레임으로 구한 후, address 데이터프레임에 통합한다. 총빈도수로 정렬한 결과는 <리스트 5>와 같다.



<리스트 5> 연설문 단어 빈도['사업', 6, 6, 0, 12],
['평화', 0, 0, 12, 12],
['법안', 1, 11, 0, 12],
['내년', 2, 10, 0, 12],
['제도', 10, 2, 1, 13],
['미래', 3, 5, 5, 13],
['관행', 9, 2, 2, 13],
['존경', 2, 6, 5, 13],
['시장', 8, 4, 1, 13],
['혁신', 13, 1, 0, 14],
['문화', 0, 10, 4, 14],
['행복', 2, 10, 3, 15],
['투자', 9, 6, 0, 15],
['민국', 1, 5, 9, 15],
['여러', 1, 10, 4, 15],
['국회', 0, 15, 0, 15],
['대한', 1, 5, 9, 15],
['규제', 12, 3, 0, 15],
['활성화', 5, 10, 1, 16],
['일자리', 5, 9, 2, 16],
['여러분', 2, 7, 7, 16],
['추진', 6, 9, 1, 16],
['강화', 11, 8, 0, 19],
['세계', 9, 6, 5, 20],
['지원', 10, 9, 1, 20],
['창조', 10, 12, 0, 22],
['확대', 21, 9, 0, 30],
['정부', 3, 25, 8, 36],
['우리', 27, 20, 16, 63],
['국민', 12, 36, 24, 72],
['경제', 42, 28, 6, 76],



‘경제’이라는 단어를 가장 많이 사용했고, ‘국민’이라는 단어도 역시 많이 사용했다. '경제'는 각각의 연설에서 42회, 28회, 6회, 총 76회 사용했다. ‘문화’, ‘존경’, ‘평화’등과 같은 단어도 사용했음을 알 수 있다.



문서 군집화

지금부터는 NMF(Non-negative matrix factorization)를 활용하여 전직 대통령 연설문을 군집화하도록 하겠다. 구현 방법은 NMF을 활용하여 두 전현직 대통령의 연설문에서 주제어를 추출한 후, 주제어를 기반으로 각 연설문과 가까운 것으로 군집화하려 한다. 두 대통령의 연설문은 각각 노무현 대통령 홈페이지(http://archives.knowhow.or.kr/archives/index.phpbId=437 &speechId=747)와 청와대 홈페이지에서 구할 수 있다. 우선, 간단하게 테스트하기 위해 각 대통령의 세 개 연설문에 적용한다. 사실, 데이터가 매우 적다. 하지만 같은 진행 방법으로 데이터를 계속 만들 수 있다. 웹에서 구한 연설을 txt 파일로 저장하고, 이 문서를 그대로 사용할 수 없기 때문에 다른 작업이 필요하다. 앞에 연설문에서 단어 빈도를 구하듯이 의미가 가장 높은 명사만 추출하기 위해 이번에도 형태소 분석을 실시한 후 다른 파일에 저장한다.



벡터화

문서를 행렬로 다룰 수 있도록 변환하도록 하자. 이러한 변환을 하기 위해 단어 주머니(bag-of-words model) 접근법을 사용한다. 연설문에 출현한 모든 단어를 세어 벡터로 나타낸다. 다시 말해, 형태소 분석을 한 후 명사로 구성된 문서에서 출현된 단어를 세어 각 문서로 적는다. 이번에는 numpy을 사용하지 않고 scikit learn에 있는 CountVectorizer을 사용하겠다. 이때, 각 연설문에 출현된 단어는 연설문마다 크게 다를 수 있기 때문에 희소 행렬을 사용하는 것이 좋다.(<리스트 6> 참조)



<리스트 6> 연설의 단어를 벡터화vectorizer = CountVectorizer(max_df=10, min_df=2)
counts = vectorizer.fit_transform(data)



<리스트 6>을 통해 우리가 다를 수 있는 행렬로 문서를 표현할 수 있다. 하지만 좀 더 나은 결과를 얻기 위해 한 번 더 처리를 할 수 있다. 이 과정은 각 단어가 특정 연설문에서 얼마나 중요한가를 측정하는 TF-IDF(Term Frequency - Inverse Document Frequency)이다. 이로써, 각 단어의 중요도를 행렬을 만들어 정확도를 높일 수 있다. scikit learn을 사용하면 상당히 간단하게 구현할 수 있다. 단어 빈도수로 구한 개체를 TfidfTransformer().fit_transform 함수에 입력만 하면 된다.



<리스트 7> TF-IDF 적용tfidf = TfidfTransformer().fit_transform(counts)



NMF(Non-negative Matrix Factorization)

비음수 행렬 인수분해(NMF, Non-negative Matrix Factor ization)는 다변향 분석(multivariate analysis) 알고리즘이다. 음수가 없는 하나의 행렬을 두 개의 음수가 없는 행렬로 한다는 게 가장 큰 차이점이다. 분해된 두 행렬 중 기저 행렬의 원소들을 더하여 원래의 행렬과 유사하게 표현할 수 있다. NMF는 이미지 등의 패턴 학습과 패턴 인식에 우수한 성능을 보인다. 특히 다수의 입력 데이터에서 최적의 기초 패턴을 분리하여 이들의 선형 조합으로 전체 데이터를 근사할 수 있기 때문에 데이터 특징 추출에 유용하다.



scikit learn에서 NMF 사용하기

scikit learn은 NMF를 지원하여 사용하기 쉽다. 벡터화 한 데이터를 입력하고 군집화 할 개수를 n_components로 설정한다. 두 개의 다른 주제어를 추출하기 위해 n_components을 2로 한다. 이게 전부이다.



<리스트 8> NMF 적용nmf = decomposition.NMF(n_components=2).fit(tfidf)
feature_names = vectorizer.get_feature_names()



모든 연설문을 두 개의 주제로 나누고, 각 연설문이 어느 주제와 유사성이 높은가로 각 연설을 군집한다. 그러면 각 주제를 살펴보자.



<리스트 9> 모든 연설을 두 개의 100개 주제어 출력for topic_idx, topic in enumerate(nmf.components_):
print "주제어 #%d:" % topic_idx
#print " ".join([str(i) for i in topic.argsort()[:-100:-1]])
print " ".join([feature_names[i] for i in topic.argsort()[:-100:-1]])



결과는 다음과 같다.



<리스트 10> 각 주제에 대한 100개의 주제어주제어 #0: 국민 우리 평화 동북아 북한 여러분 한반도 시대 세계 역사 정부 사회 문화 신뢰 경제 여러 민국
대한 협력 정치 대화 오늘 나라 활력 존경 도전 번영 올해 진정 과거 위대 마음 미래 남북관계 남북한
노력 저력 문제 비롯 극복 대통령 지속 국제 국가 최선 감사 원칙 지혜 자랑 타협 행복 적극 사람
지난해 안보 과제 기회 어려움 여정 내수 해결 하나 개혁 건강 발전 시작 용기 희망 실행 혼란
수립 기록 회복 고통 중국 분단 동참 로운 계기 정책 추진 청산 하기 농어민 성찰 지역구 전기
우려 바다 민주주의 정치권 안정 변화 수출 정착 성과 자리 환경 이후주제어 #1: 경제 확대 우리 규제 국민 혁신 정부 투자 참여 창조 강화 추진 지원 국회 세계
fta 노력 시장 법안 한국 사업 수출 일자리 해서 투명 제도 도입 여러 민간 변화 문제 관행
해결 중심 전략 내년 통과 활성화 공공기관 전환 창업 지방 분야 확충 지역 발전 모두 청년
성장 적극 행복 문화 투명성 산업 개혁 경영 극복 생각 속도 국가 아이디어 관련 가계부채
고용 개방 기초 내수 제조업 마련 사회 북핵문제 중요 확신 중소기업 재정 규모 국내 창출
경쟁력 비정상 체제 안정 지속 기업 수준 지금 방향 시스템 구축 주택 국제 대비 사회안전
개선 대기업 회의 진행 체결 획기적



두 주제들이 매우 비슷해 보이지만 약간의 차이가 있다. 주제어 #0은 ‘한반도’, ‘남북관계’, ‘평화’등 노무현 대통령이 잘 사용하던 단어들이 보인다. 반면, 주제어 #1은 ‘창조’, ‘활성화’, ‘비정상’등 박근혜 대통령이 잘 사용하는 단어가 눈에 띈다. 이를 근거로, 자의적으로 주제어 #0은 노무현 대통령의 연설의 주제어로, 주제어 #1은 박근혜 대통령의 연설의 주제어로 상정한다. .

두 주제의 주제어들은 두 대통령의 연설문을 구별할 수 있드 거리로 유사도를 구해보자. 연설문의 처음 세 개, 나중 세 개는 각각 노무현, 박근혜 대통령의 연설문이다.



<리스트 11> 모든 연설을 두 개의 100개 주제어 출력euclidean_distances(nmf.components_, tfidf[0,:])
euclidean_distances(nmf.components_, tfidf[1,:])
euclidean_distances(nmf.components_, tfidf[2,:])
euclidean_distances(nmf.components_, tfidf[3,:])
euclidean_distances(nmf.components_, tfidf[4,:])
euclidean_distances(nmf.components_, tfidf[5,:])



결과는 <리스트 12>와 같다.



<리스트 12> 두 주제와 각 연설문의 유클리드 거리 값[[ 0.62287387]
[ 1.11164836]]
[[ 0.95228404]
[ 1.07534403]]
[[ 1.28511981]
[ 0.68263318]]
[[ 1.3314363]
[ 0.5014573]]
[[ 1.08667377]
[ 0.68817885]]
[[ 0.58665335]
[ 1.12390923]]



첫 번째 연설은 [[ 0.62287387] [ 1.11164836]]으로 주제어 #0에 가깝다. 즉, 노무현 대통령의 연설문을 노무현 대통령 주제로 찾아냈다. 총 6개중 4개는 정확하게 맞추었으나 2개는 잘못 분류했다. 이유는 여러 가지일 수 있으나 가장 의심스러운 부분은 학습 데이터가 너무 적어 생길 수 있는 문제일 수 있다는 점이다.



k-평균(k-means)

여기서 다른 기법으로 군집화를 할 수도 있다. k-평균(k- means) 기법을 적용해 보자. 데이터는 그대로 사용하며, scikit learn 큰 장점인 모든 학습기의 같은 인터페이스로 학습기만 변경한다. 다음은 knn을 사용한 코드이다.



<리스트 13> 모든 연설을 두 개의 100개 주제어 출력km = KMeans(n_clusters=2, init='random')
km.fit(tfidf)
print km.labels_



결과는 다음과 같다.



<리스트 14> 모든 연설을 두 개의 100개 주제어 출력[0 0 1 1 1 0]



정확히 NMF로 구한 결과와 같다. 즉, 처음 2개의 연설문은 정확히 지정하였으나 나머지 하나와 마지막 6번째 연설문을 잘못 지정하였다. 잘못 분류된 연설문은 다른 주제어와 유사하여 이와 같은 결과를 나타날 수 있음을 짐작할 수도 있다.



결론

지금까지 대통령 연설을 분류해 보았다. 대통령의 연설에는 분명한 차이점이 있었음을 알 수 있다. 관련 코드는 https://github.com/brenden17/president-speech/blob/master/.ipynb_checkpoints/president-speech-checkpoint.ipynb에서 볼 수 있다. 연설문의 의미를 기계 학습으로 정확히 추정할 수는 없지만 사용한 단어의 빈도를 활용하여 연설문의 강조점을 알 수 있으며, 다른 연설의 차이점을 구별할 수 있다.



출처 : 마이크로소프트웨어 9월호

제공 : 데이터 전문가 지식포털 DBguide.net