- 전체
- Python 일반
- Python 수학
- Python 그래픽
- Python 자료구조
- Python 인공지능
- Python 인터넷
- Python SAGE
- wxPython
- TkInter
- iPython
- wxPython
- pyQT
- Jython
- django
- flask
- blender python scripting
- python for minecraft
- Python 데이터 분석
- Python RPA
- cython
- PyCharm
- pySide
- kivy (python)
Python 인공지능 파이썬으로 3줄 요약기를 만들어보자.
2018.03.04 14:01
파이썬으로 3줄 요약기를 만들어보자.
자동으로 요약해주는 알고리즘에는 다양한 방법이 있지만 여기서는 본문의 문장을 그대로 활용하는 Extraction-based summarization을 사용할 것이다.
단순하게는 각 문장별로 중요도를 annotate한 후에 높은 순서대로 출력하면 방법이 있을테고, 그 ‘중요도'를 어떻게 측정하냐가 문제다. 이는 가장 유명하면서도 단순한 TextRank 알고리즘으로 시험 해볼 수 있다.
TextRank 알고리즘은 구글의 PageRank 알고리즘을 기반으로 되어있다. PageRank에 대해선 이 글에서 재밌게 소개가 되어있으니 읽어보면 좋다.
PageRank 알고리즘의 기본 원리는 그래프로 데이터를 표현한 후, 각 edge의 값이 영향력을 행사한다고 보고 가장 중요한 node를 찾는 것이다. 비슷하게 어떤 글의 문장들도 서로 영향력을 행사한다고 생각하고, 여기서 가장 중요한 문장을 찾으면 된다.
우선 주어진 글을 문장별로 쪼개보자.
import re
def xplit(*delimiters):
return lambda value: re.split('|'.join([re.escape(delimiter) for delimiter in delimiters]), value)
xplit('. ', '? ', '! ', '\n', '.\n')("This is a sentence. Here is another sentence.\nHello, world!")
# ['This is a sentence', 'Here is another sentence', 'Hello, world!']
이렇게 rule-based로 문장을 구분하는건 그닥 좋은 방법이 아니지만, 널리 알려진 한국어 형태소 분석기들 중에선 빠르고 적절하며 원문을 보존하며 문장 구분을 해주는 기능이 구현된게 없고 이렇게 해도 일단은 큰 무리 없이 문장을 잘라준다.
첨언하자면 KoNLPy에 들어있는 형태소 분석기들 중 꼬꼬마는 문장을 잘라주는 기능이 있지만 이는 POS 태깅을 전부 한 후에 학습된 문장 구분자로 잘라서 POS가 띄어쓰기로 나눠진채 반환하기 때문에 원문이 유지되지 않는다.
from konlpy.tag import Kkma
kkma = Kkma()
kkma.sentence("이세돌은 알파고를 이겼다. 이세돌은 강하다. 알파고도 짱쎔.")
# ['이세 돌은 알 파고를 이겼다.', '이세 돌은 강하다.', '알 파고도 짱 쎔.']
다음으로는 이제 '문장간 영향력을 행사한다'를 정의할 차례다. 여러가지 방법이 있겠지만 가장 쉽게 '두 문장의 공통으로 등장하는 명사에 의한 유사도'로 해보자. Similarity라는 것은 symmetric하기 때문에, 두 문장은 서로에게 동일한 값 만큼 영향력을 주게된다.
우선 명사는 다음과 같이 얻어낼 수 있다.
kkma.nouns("눈보라에 차갑게 얼린 머리카락 먹고싶다.")
# ['눈보라', '머리카락']
실제로는 POS 태깅을 한 후에 결과가 명사라고 볼 수 있는 것들을 필터링해서 반환해주는 함수다.
같은 명사가 한 문장에 여러개 나올 수도 있다. 꼬꼬마는 중복을 제거하니까 트위터 형태소 분석기를 사용해보자.
from konlpy.tag import Twitter
twitter = Twitter()
twitter.nouns("미쿠 미쿠 하게 해줄게")
# ['미쿠', '미쿠']
이제 얻어낸 명사들을 Bag-of-words, 혹은 멀티셋 즉 중복을 허용하는 집합으로 표현해놓자. 유사도는 단순히 두 문장에서 어떤 명사가 공통으로 (얼마나) 들어있나 안들어있나로 계산 할 것이기에 순서를 고려하지 않기로 한다. 그리고 파이썬엔 마침 Counter라는게 존재한다.
from collections import Counter
bow1 = Counter(twitter.nouns("미쿠 미쿠 하게 해줄게"))
# Counter({'미쿠': 2})
bow2 = Counter(twitter.nouns("미쿠 머리카락 맛있겠다"))
# Counter({'미쿠': 1, '머리카락': 1})
두 멀티셋의 유사도는 Jaccard Index를 사용할 것이다. 식은 아래와 같다.
멀티셋에서의 합집합은 key가 어느 집합에 있고, 그 수는 최대값. 그리고 교집합은 반대로 key가 두 집합 모두 있고, 그 수는 최소값이 되도록 정의된다. 예를 들면 다음과 같다:
그리고 매우 편리하게도 Counter가 이런걸 다 알아서 해준다!
j_index = sum((bow1 & bow2).values()) / sum((bow1 | bow2).values())
# 0.3333333333333333
이제 '문장간 영향력을 행사하는 정도'가 정의 되었다. 두 문장에서 공통으로 등장하는 명사들을 멀티셋으로 만든 후 나오는 Jaccard Index의 값을 '서로에게 이만큼 영향을 준다'로 정의한 것이다.
사실 이 말고도 여러가지 방법이 있다. 명사 말고 동사도 포함시켜도 되고, 레벤슈타인 거리를 사용해도 되고, TF-IDF를 계산해서 문장간의 각도를 사용해도 된다.
여튼 이제 문장을 node로 뒀을때 edge에 부여할 값을 계산 할수 있게 되었으니 남은건 이걸로 그래프를 그리고 거기서 PageRank를 돌리는 것이다.
그리고 이건 파이썬 라이브러리인 NetworkX가 알아서 다 해준다!
실제로 구현을 해보자면 일단 Sentence 클래스를 만들고
class Sentence:
@staticmethod
def co_occurence(sentence1, sentence2):
p = sum((sentence1.bow & sentence2.bow).values())
q = sum((sentence1.bow | sentence2.bow).values())
return p / q if q else 0
def __init__(self, text, index=0):
self.index = index
self.text = text
self.nouns = twitter.nouns(self.text)
self.bow = Counter(self.nouns)
def __eq__(self, another):
return hasattr(another, 'index') and self.index == another.index
def __hash__(self):
return self.index
(여기서 index는 원문에서의 문장 위치를 나타내는데 쓰인다) 주어진 글을 이 Sentence 인스턴스의 리스트로 반환해주자.
def get_sentences(text):
candidates = xplit('. ', '? ', '! ', '\n', '.\n')(text.strip())
sentences = []
index = 0
for candidate in candidates:
candidate = candidate.strip()
if len(candidate):
sentences.append(Sentence(candidate, index))
index += 1
return sentences
이를 활용하여 그래프를 만들면 다음과 같이 된다. 각 edge의 weight가 두 문장 간의 Jaccard Index가 되도록.
def build_graph(sentences):
graph = networkx.Graph()
graph.add_nodes_from(sentences)
pairs = list(itertools.combinations(sentences, 2))
for eins, zwei in pairs:
graph.add_edge(eins, zwei, weight=Sentence.co_occurence(eins, zwei))
return graph
이제 NetworkX의 pagerank 함수까지 사용해서 전체적으로 쭉 돌려보면
sentences = get_sentences(text)
graph = build_graph(sentences)
pagerank = networkx.pagerank(graph, weight='weight')
reordered = sorted(pagerank, key=pagerank.get, reverse=True)
가 된다. 이제 reordered[0]엔 이 알고리즘이 생각하기에 가장 중요한 문장이 들어있을 것이다.
사실 이 방법은 문서 요약에 있어서 그닥 유효한 전략은 아니다. 문장간 영향을 주는것도 symmetric하고 결과적으로 '가장 중요한 단어가 가장 많이 들어간 문장'이 나오는데 이게 꼭 좋은 요약이 되지는 않으며 모든 문서에서 항상 통하는건 아니기 때문이다.
간단하게는 여기서 테스트를 해볼 수 있다. 자세한 소스코드는 (이 글에서 소개한 것과 100% 일치하지는 않지만) 깃헙에 올려뒀고, PyPI에도 올라가 있으므로 간단하게
pip install textrankr
로 설치해서 사용해볼 수 있다. 참고로 이 코드는 미흡한 점이 매우 많다.. PR 호시이
여튼, 3줄 요약기는 간단하게 이런 방법으로 구현해볼 수 있다.
[출처] http://blog.theeluwin.kr/post/146188165713/summariz3
[출처] https://github.com/theeluwin/textrankr
TextRank for Korean
Reorder sentences using TextRank algorithm. Click here to see how to install KoNLPy properly.
Upgraded version named lexrankr using LexRank is available too!
Installation
pip install textrankr
Usage
from __future__ import print_function
from textrankr import TextRank
textrank = TextRank(your_text_here)
print(textrank.summarize())
Test
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
댓글 0
| 번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
|---|---|---|---|---|
| 10 |
[Kivy (python)] Kivy에서 Hello World
| 졸리운_곰 | 2024.12.20 | 358 |
| 9 |
[Kivy (python)] Kivy 시작하기 1 (1.11.1 버전 - 설치하기)
| 졸리운_곰 | 2024.12.20 | 401 |
| 8 | [Kivy (python)] Kivy 앱 배포: Android APK 생성하기 | 졸리운_곰 | 2024.12.20 | 347 |
| 7 |
[kivy (python)] [Python] 파이썬 키비(kivy) 앱 개발 - Screen Manager
| 졸리운_곰 | 2024.12.20 | 509 |
| 6 |
[kivy (python)] [Python] 파이썬 키비(kivy) 앱 개발 - 머티리얼 디자인, KivyMD
| 졸리운_곰 | 2024.12.20 | 392 |
| 5 |
[kivy (python)] [Python] 파이썬 키비(kivy) 앱 개발 - 레이아웃 개요와 입력창
| 졸리운_곰 | 2024.12.20 | 495 |
| 4 |
[kivy (python)] [Python] 파이썬 키비(Kivy) buildozer로 APK 앱 빌드 in Linux
| 졸리운_곰 | 2024.12.20 | 383 |
| 3 |
[kivy (python)] [Python] 파이썬 키비(kivy) 앱 개발 - 설치와 예제 앱 분석
| 졸리운_곰 | 2024.12.20 | 427 |
| 2 |
[kivy (python)] [Python] 파이썬 키비(kivy) 앱 개발 - kv 파일과 한글 폰트
| 졸리운_곰 | 2024.12.20 | 385 |
| 1 |
[kivy (python)] <재정리> 파이썬 키비(Kivy) buildozer로 APK 앱 완벽 변환하기 in Linux Ubuntu, 변환 환경 제공!
| 졸리운_곰 | 2024.12.20 | 598 |

