명사 분리 추출 후, 단어 사용 빈도 계산하기
이번에는 동아일보, 한겨레신문에서 '사드'관련 기사를 크롤링해 저장한 텍스트 파일을 이용해 단어 사용 빈도를 계산하는 프로그램을 만들어보겠습니다.
""" 형태소 분석기
명사 추출 및 빈도수 체크
python [모듈 이름] [텍스트 파일명.txt] [결과파일명.txt]
"""
import sys
from konlpy.tag import Twitter
from collections import Counter
def get_tags(text, ntags=50):
spliter = Twitter()
nouns = spliter.nouns(text)
count = Counter(nouns)
return_list = []
for n, c in count.most_common(ntags):
temp = {'tag': n, 'count': c}
return_list.append(temp)
return return_list
def main(argv):
if len(argv) != 4:
print('python [모듈 이름] [텍스트 파일명.txt] [단어 개수] [결과파일명.txt]')
return
text_file_name = argv[1]
noun_count = int(argv[2])
output_file_name = argv[3]
open_text_file = open(text_file_name, 'r')
text = open_text_file.read()
tags = get_tags(text, noun_count)
open_text_file.close()
open_output_file = open(output_file_name, 'w')
for tag in tags:
noun = tag['tag']
count = tag['count']
open_output_file.write('{} {}\n'.format(noun, count))
open_output_file.close()
if __name__ == '__main__':
main(sys.argv)
위 코드는 사용자로부터 텍스트를 입력받아 명사를 분리/추출해 단어사용 빈도를 계산하는 모듈입니다.
코드 한줄한줄 자세히 살펴보겠습니다.
mport sys
from konlpy.tag import Twitter
from collections import Counter
이전 글의 크롤러 모듈에서와 마찬가지로 해당 모듈을 실행할 때, 터미널에서 사용자로부터 인자를 받기 위해 'sys.argv'를 사용하려고 'sys'를 임포트 했습니다. 그리고 명사를 분리/추출하기 위해 한국어 형태소 분석기인 'konlpy'를 임포트 했습니다. 특히, 저는 여기서 'konlpy'의 여러 품사 태깅 클래스 중 'Twitter'를 사용했습니다.
(konlpy.tag 안에는 Kkma, Komoran, Hannanum, Twitter, Mecab 등의 여러 품사 태깅 클래스가 있습니다. 여기서 저는 Twitter를 사용했습니다. Hannanum 클래스의 경우, 정확한 이유는 모르겠지만 텍스트의 길이가 길어져 사용된 단어가 많아지면 올바르게 실행이 안 되는 문제가 있는 것 같습니다. 참고하시기 바랍니다. konlpy의 설치법과 더 많은 정보를 원하시는 분들은 'konlpy 공식 홈페이지' 를 참조하시기 바랍니다. )
collections의 Counter객체는 counting hashable container 객체로서 간단히 말해, 빈도수 계산을 위한 사전 형태의 데이터 타입입니다. 'konlpy'를 통해 품사 태깅을 한 후, 명사만 따로 모아 빈도수를 계산하기 위해 임포트 했습니다.
def get_tags(text, ntags=50):
spliter = Twitter()
nouns = spliter.nouns(text)
count = Counter(nouns)
return_list = []
for n, c in count.most_common(ntags):
temp = {'tag': n, 'count': c}
return_list.append(temp)
return return_list
위 코드는 텍스트에서 명사를 분리/추출한 후, 빈도 계산을 하는 함수입니다.
해당 함수의 인자 중, 'text'는 분석에 사용할 텍스트이며, 'ntags'는 분리한 명사 중 결과를 출력할 명사의 개수입니다. 'ntags'는 키워드 인자로 디폴트 값으로 50을 설정했습니다. 즉, 사용자로부터 아무 입력이 없으면 해당 함수는 빈도수 기준으로 상위 50개의 명사의 결과만 출력합니다.
함수가 실행되면 우선 'Twitter'객체를 생성합니다. 이후, 'Twitter'객체의 'nouns'메서드를 이용해 'text'에서 명사만 분리/추출합니다. 'Twitter'객체의 'nouns'메서드는 결과 값으로 순환 가능한 객체를 반환합니다. 다시 말해, 참조 변수 'nouns'에는 'Twitter'객체의 'nouns'메서드에 의해 분리/추출된 명사들이 순환 가능한 객체로 저장되어 있습니다.
('Twitter'객체를 통해 'nouns'품사 말고도 'Josa', 'Verb', 'Eomi' 등의 다른 품사도 추출할 수 있습니다. 공식 홈페이지를 참조세요.)
이후, 이 객체를 이용해 'Counter'객체를 생성하고, 이를 참조 변수 'count'에 할당합니다. 위에서 설명했듯이 'Counter'객체는 빈도 계산을 위한 사전 객체로 명사의 사용 빈도를 계산하기 위해 생성했습니다. 그 후, 명사 별 빈도수를 저장하기 위한 리스트인 'return_list'를 선언합니다.
그다음 for문에서는 다음과 같은 작업이 수행됩니다. 'Counter'객체의 'most_common'메서드는 정수를 입력받아 객체 안의 명사 중, 빈도수가 큰 명사부터 순서대로 입력받은 정수 개수만큼 저장되어 있는 객체를 반환합니다. 따라서 for문을 통해 해당 객체에 접근을 한 후, 참조 변수 'n'에는 명사를, 참조변수 'c'에는 해당 명사의 빈도수를 할당받아 'tag'키값에는 명사(n)를, 'count'키값에는 해당 명사의 빈도를 갖는 딕셔너리를 만들어 저장하고 이를 결과 리스트인 'return_list'에 순서대로 삽입합니다. 해당 함수의 'ntags'는 디폴트 값으로 50이 설정되어 있으므로 별도의 설정이 없다면 해당 함수는 빈도수 기준 상위 50개의 명사만 결괏값으로 반환할 것입니다.
for문이 종료된 후에는 'return_list'를 반환합니다. 'return_list'의 예시 형태는 다음과 같습니다.
[{'tags': '명사1', 'count': N1}, {'tags': '명사2', 'count': N2}, ... ,{'tags': '명사50', 'count': N50}]
(N1 >= N2 >= N3 >= .... >= N50)
만약 반환된 결과가 'ntags'수만큼 나오지 않았다면, 사용된 단어가 그 수보다 적은 것입니다.
def main(argv):
if len(argv) != 4:
print('python [모듈 이름] [텍스트 파일명.txt] [단어 개수] [결과파일명.txt]')
return
text_file_name = argv[1]
noun_count = int(argv[2])
output_file_name = argv[3]
open_text_file = open(text_file_name, 'r')
text = open_text_file.read()
tags = get_tags(text, noun_count)
open_text_file.close()
open_output_file = open(output_file_name, 'w')
for tag in tags:
noun = tag['tag']
count = tag['count']
open_output_file.write('{} {}\n'.format(noun, count))
open_output_file.close()
if __name__ == '__main__':
main(sys.argv)
위 코드는 메인 함수입니다. 사용자로부터 읽어 올 파일명, 뽑아올 명사 개수, 결과를 저장할 파일명을 입력받아 각각 'text_file_name', 'noun_count', 'output_file_name'에 할당합니다. 'noun_count'의 경우 정수형으로 캐스팅했습니다.
이후, 분석할 텍스트를 읽어와 'text'에 할당하고, 위에서 설명한 'get_tags'함수를 통해 명사 분석 결과를 참조 변수 'tags'에 할당합니다. 그다음 결과 파일명을 통해 결과 파일을 생성하고 for문을 통해 'tags'에 저장된 분리된 명사와 해당 명사의 사용 빈도수를 결과 파일에 콤마(,)로 구분해 write 합니다.
결과 파일 형식은 다음과 같습니다.
명사1, N1명사2, N2명사3, N3 . . .
(N1 >= N2 >= N3 >= ...)
(좌 동아일보, 우 한겨레신문)
위 모듈을 통해 동아일보와 한겨레신문에서 사드 관련 기사를 크롤링해와 사용된 명사의 빈도수를 추출한 결과입니다. 두 신문사의 기사 모두 총 50개의 명사를 추출했습니다. 보시다시피 두 신문사 모두 '사드'와 '배치'를 제일 많이 사용한 것을 알 수 있습니다. 그 이후에 사용된 단어와 빈도수 순위는 신문사별로 조금씩 달랐습니다.
중간중간 '수', '등', '그', '며' 등의 무의미한 명사와 명사 형태가 아닌 단어도 추출된 것이 보이는데, 이는 'Twitter' 품사 태깅 클래스에서 걸러주지 못한 것이므로 수작업으로 제거한 후, 시각화 또는 분석에 사용하시면 됩니다.
다음 마지막 글에서는 계산한 명사의 빈도수를 바탕으로 워드 클라우드로 시각화하는 프로그램을 만들어보도록 하겠습니다.