


from sumy.parsers.plaintext import PlaintextParser
from sumy.nlp.tokenizers import Tokenizer
from sumy.summarizers.text_rank import TextRankSummarizer
text = """
And she won't eat her dinner - rice pudding again -
I've promised her dolls and a daisy-chain,
I've promised her sweets and a ride in the train,
And it's lovely rice pudding for dinner again!
"""
parser = PlaintextParser.from_string(text, Tokenizer("english"))
summarizer = TextRankSummarizer()
summary_sentences = summarizer(parser.document, 2)
for sentence in summary_sentences:
print(sentence)
from sumy.parsers.plaintext import PlaintextParser
from sumy.nlp.tokenizers import Tokenizer
from sumy.summarizers.text_rank import TextRankSummarizer
PlaintextParser: 일반 텍스트 문자열을 분석할 수 있는 형태로 변환합니다.
Tokenizer: 문장을 단어 단위로 쪼개는 역할을 합니다 (언어별 처리를 위함).
TextRankSummarizer: 요약 알고리즘인 TextRank를 불러옵니다.
text = """... (시 내용) ..."""
parser = PlaintextParser.from_string(text, Tokenizer("english"))
from_string: 문자열(text)을 입력받습니다.
Tokenizer("english"): 영어 텍스트임을 명시하여, 영어 문법에 맞게 토큰화(단어 분리)를 수행하도록 설정합니다.
이번 실습에서는 문장 간의 관계를 그래프로 이해하는 방식을 통해 TextRank 알고리즘의 핵심 원리를 학습했다.
TextRank는 NLP에서 비교적 고전적인 알고리즘이지만, 구조 자체는 여전히 강력하다는 점이 인상 깊었다.
특히 추출 요약(Extractive Summarization) 개념을 명확히 이해할 수 있었다.
요약이라고 해서 문장을 새로 생성하는 것이 아니라, 원문에 존재하는 문장 중에서 가장 중요한 문장을 그대로 선택해 가져오는 방식이라는 점이 명확해졌다.
또한 TextRank가 그래프 기반 알고리즘이라는 점도 흥미로웠다.
각 문장을 노드(Node)로 보고, 문장 간 유사도를 엣지(Edge)로 연결한 뒤,
구글의 PageRank와 유사한 방식으로 중요도를 계산해 핵심 문장을 찾는 구조라는 점을 이해했다.
전체적인 NLP 처리 흐름도 다시 정리할 수 있었다.
텍스트 입력부터 시작해서 토큰화 → 파싱 → 요약기로 이어지는 파이프라인을 직접 따라가 보면서,
이론으로만 알던 NLP 처리 과정이 실제로 어떻게 연결되는지 감이 잡혔다.
# -*- coding: utf-8 -*-
import re
from sumy.parsers.plaintext import PlaintextParser
text = """Rice Pudding - Poem by Alan Alexander Milne
... What is the matter with Mary Jane?
... She's crying with all her might and main,
... And she won't eat her dinner - rice pudding again -
... What is the matter with Mary Jane?
... What is the matter with Mary Jane?
... I've promised her dolls and a daisy-chain,
... And a book about animals - all in vain -
... What is the matter with Mary Jane?
... What is the matter with Mary Jane?
... She's perfectly well, and she hasn't a pain;
... But, look at her, now she's beginning again! -
... What is the matter with Mary Jane?
... What is the matter with Mary Jane?
... I've promised her sweets and a ride in the train,
... And I've begged her to stop for a bit and explain -
... What is the matter with Mary Jane?
... What is the matter with Mary Jane?
... She's perfectly well and she hasn't a pain,
... And it's lovely rice pudding for dinner again!
... What is the matter with Mary Jane?"""
# --------------------------------------------
# ✅ 전처리: gensim/sumy/transformers 모두 문장 경계가 중요
# - "..." 같은 패턴이 많으면 문장 분리가 흐트러져 요약 품질이 급락함
# --------------------------------------------
def clean_text(t: str) -> str:
t = t.replace("\r\n", "\n")
t = re.sub(r"\n{2,}", "\n\n", t)
t = re.sub(r"^\s*\.\.\.\s*", "", t, flags=re.MULTILINE) # 줄 앞 "... " 제거
return t.strip()
text = clean_text(text)
# --------------------------------------------
# ✅ 1순위: Transformers 추상 요약(품질 좋음)
# - 영어: facebook/bart-large-cnn
# - 한국어: gogamza/kobart-summarization (원하면 아래 model_name만 바꾸면 됨)
# --------------------------------------------
def summarize_with_transformers(t: str, model_name: str, max_len=120, min_len=30):
from transformers import pipeline
# device=-1 : CPU
summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
out = summarizer(t, max_length=max_len, min_length=min_len, do_sample=False)
return out[0]["summary_text"]
# --------------------------------------------
# ✅ 2순위: sumy 추출 요약(가벼움/설치 쉬움)
# - 영어는 LexRank가 무난
# - 한국어는 sumy 토크나이저가 제한적이라(정확도↓) 영어에 더 적합
# --------------------------------------------
def summarize_with_sumy_lexrank(t: str, sentences=3, language="english"):
from sumy.parsers.plaintext import PlaintextParser
from sumy.nlp.tokenizers import Tokenizer
from sumy.summarizers.lex_rank import LexRankSummarizer
parser = PlaintextParser.from_string(t, Tokenizer(language))
summarizer = LexRankSummarizer()
summary = summarizer(parser.document, sentences)
return "\n".join(str(s) for s in summary)
# --------------------------------------------
# ✅ 실행: transformers -> 실패하면 sumy로 fallback
# --------------------------------------------
try:
# 영어 요약 (시)
print("[Transformers: BART 요약]")
print(summarize_with_transformers(text, model_name="facebook/bart-large-cnn"))
except Exception as e:
print("[Transformers 요약 실패] -> sumy로 대체합니다.")
print("원인:", repr(e))
print("\n[Sumy: LexRank 요약]")
print(summarize_with_sumy_lexrank(text, sentences=4, language="english"))
(venv_nlp) apple@apples-MacBook-Air pythoncode % /Users/apple/Desktop/pythoncode/venv_nlp/bin/python
"/Users/apple/Desktop/pythoncode/1512_실행_TextRank를 이용한 추출 요약.py"
[Transformers: BART 요약]
[Transformers 요약 실패] -> sumy로 대체합니다.
원인: KeyError("Unknown task summarization, available tasks are ['any-to-any', 'audio-classification', 'automatic-speech-recognition', 'depth-estimation', 'document-question-answering', 'feature-extraction', 'fill-mask', 'image-classification', 'image-feature-extraction', 'image-segmentation', 'image-text-to-text', 'image-to-image', 'keypoint-matching', 'mask-generation', 'ner', 'object-detection', 'question-answering', 'sentiment-analysis', 'table-question-answering', 'text-classification', 'text-generation', 'text-to-audio', 'text-to-speech', 'token-classification', 'video-classification', 'visual-question-answering', 'vqa', 'zero-shot-audio-classification', 'zero-shot-classification', 'zero-shot-image-classification', 'zero-shot-object-detection', 'translation_XX_to_YY']")
[Sumy: LexRank 요약]
She's crying with all her might and main, And she won't eat her dinner - rice pudding again - What is the matter with Mary Jane?
What is the matter with Mary Jane?
I've promised her sweets and a ride in the train, And I've begged her to stop for a bit and explain - What is the matter with Mary Jane?
She's perfectly well and she hasn't a pain, And it's lovely rice pudding for dinner again!
이 글은 텍스트 요약(Text Summarization) 실습 코드가
어떤 흐름으로 동작하고, 각 코드가 어떤 역할을 하는지를
프로그래밍 관점과 NLP 관점에서 정리한 설명이다.
이 코드는 하나의 긴 텍스트를 입력으로 받아 다음 순서로 처리한다.
즉, 항상 요약 결과를 보장하는 요약 파이프라인이다.
re
정규표현식을 이용한 문자열 전처리를 위해 사용된다.
sumy.parsers.plaintext.PlaintextParser
텍스트를 문장 단위로 분리하여 sumy 내부에서 처리 가능한 문서 객체로 변환하는 역할을 한다.
이 단계에서는 아직 요약을 수행하지 않고,
“무엇을 사용할지 선언”하는 준비 단계에 해당한다.
입력 데이터는 Alan Alexander Milne의 시(Rice Pudding)이다.
특징은 다음과 같다.
따라서 전처리가 필수적이다.
이 함수의 목적은 단 하나다.
요약 알고리즘이 문장을 정확히 인식하도록 텍스트를 정리하는 것
주요 작업은 다음과 같다.
이 단계가 없으면 요약 품질이 급격히 떨어진다.
전처리는 요약 성능의 절반 이상을 차지한다고 봐도 된다.
summarize_with_transformers 함수는
딥러닝 기반 추상 요약(abstractive summarization) 을 담당한다.
핵심 특징은 다음과 같다.
동작 흐름은 다음과 같다.
이 방식은 품질은 매우 높지만,
summarize_with_sumy_lexrank 함수는
전통적인 추출 요약(extractive summarization) 을 담당한다.
이 방식의 특징은 다음과 같다.
동작 원리는 다음과 같다.
LexRank는 TextRank 계열 알고리즘 중 하나다.
실행부는 다음과 같은 철학을 가진 구조다.
이는 실무 코드에서 매우 중요한 패턴이다.
딥러닝 모델은 환경 문제, 메모리 문제, 다운로드 문제로 실패할 수 있기 때문에
항상 대체 수단을 준비해야 한다.
Transformers(BART) 요약
모델 다운로드 및 환경 문제로 실패하거나 오래 걸릴 수 있음
Sumy(LexRank) 요약
즉시 실행되며 안정적으로 결과 출력
이 실습의 핵심은
“어떤 방식이 더 좋다”가 아니라
두 방식의 차이와 장단점을 직접 비교하는 것이다.
이 코드는
전통 NLP 요약과 딥러닝 요약을 하나의 흐름에서 비교하고,
실패 시 자동으로 대체하는 텍스트 요약 실습 코드이다.
# -*- coding: utf-8 -*-
import re
from sumy.parsers.plaintext import PlaintextParser
text = """Rice Pudding - Poem by Alan Alexander Milne
... What is the matter with Mary Jane?
... She's crying with all her might and main,
... And she won't eat her dinner - rice pudding again -
... What is the matter with Mary Jane?
... What is the matter with Mary Jane?
... I've promised her dolls and a daisy-chain,
... And a book about animals - all in vain -
... What is the matter with Mary Jane?
... What is the matter with Mary Jane?
... She's perfectly well, and she hasn't a pain;
... But, look at her, now she's beginning again! -
... What is the matter with Mary Jane?
... What is the matter with Mary Jane?
... I've promised her sweets and a ride in the train,
... And I've begged her to stop for a bit and explain -
... What is the matter with Mary Jane?
... What is the matter with Mary Jane?
... She's perfectly well and she hasn't a pain,
... And it's lovely rice pudding for dinner again!
... What is the matter with Mary Jane?"""
# --------------------------------------------
# ✅ 전처리: gensim/sumy/transformers 모두 문장 경계가 중요
# - "..." 같은 패턴이 많으면 문장 분리가 흐트러져 요약 품질이 급락함
# --------------------------------------------
def clean_text(t: str) -> str:
t = t.replace("\r\n", "\n")
t = re.sub(r"\n{2,}", "\n\n", t)
t = re.sub(r"^\s*\.\.\.\s*", "", t, flags=re.MULTILINE) # 줄 앞 "... " 제거
return t.strip()
text = clean_text(text)
# --------------------------------------------
# ✅ 1순위: Transformers 추상 요약(품질 좋음)
# - 영어: facebook/bart-large-cnn
# - 한국어: gogamza/kobart-summarization (원하면 아래 model_name만 바꾸면 됨)
# --------------------------------------------
def summarize_with_transformers(t: str, max_len=120, min_len=30):
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
model_name = "facebook/bart-large-cnn"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
inputs = tokenizer(
t,
max_length=1024,
truncation=True,
return_tensors="pt"
)
summary_ids = model.generate(
inputs["input_ids"],
max_length=max_len,
min_length=min_len,
num_beams=4,
early_stopping=True
)
return tokenizer.decode(summary_ids[0], skip_special_tokens=True)
# --------------------------------------------
# ✅ 2순위: sumy 추출 요약(가벼움/설치 쉬움)
# - 영어는 LexRank가 무난
# - 한국어는 sumy 토크나이저가 제한적이라(정확도↓) 영어에 더 적합
# --------------------------------------------
def summarize_with_sumy_lexrank(t: str, sentences=3, language="english"):
from sumy.parsers.plaintext import PlaintextParser
from sumy.nlp.tokenizers import Tokenizer
from sumy.summarizers.lex_rank import LexRankSummarizer
parser = PlaintextParser.from_string(t, Tokenizer(language))
summarizer = LexRankSummarizer()
summary = summarizer(parser.document, sentences)
return "\n".join(str(s) for s in summary)
# --------------------------------------------
# ✅ 실행: transformers -> 실패하면 sumy로 fallback
# --------------------------------------------
try:
print("[Transformers: BART 요약]")
print(summarize_with_transformers(text))
except Exception as e:
print("[Transformers 요약 실패] -> sumy로 대체합니다.")
print("원인:", repr(e))
print("\n[Sumy: LexRank 요약]")
print(summarize_with_sumy_lexrank(text, sentences=4, language="english"))
Transformers: BART 요약]
Please make sure the generation config includes forced_bos_token_id=0.
Loading weights: 100%|█| 511/511
[00:00<00:00, 4153.12it/s, Materializing param=model.encoder.layers
Rice Pudding - Poem by Alan Alexander Milne. Poem was written by Milne for his daughter Mary Jane. The poem was written in memory of Mary Jane, who died in a car accident.
clean_text 함수는 요약 품질을 좌우하는 핵심 단계다.
"..." 패턴을 제거한다이 전처리가 없으면:
summarize_with_transformers 함수는 딥러닝 기반 추상 요약을 담당한다.
동작 흐름은 다음과 같다.
이 방식의 특징:
summarize_with_sumy_lexrank 함수는 전통 NLP 기반 추출 요약이다.
특징:
실행부에서는 다음 전략을 사용한다.
이 구조는 실제 서비스 코드에서도 자주 사용되는 패턴이다.