티스토리 뷰
학습목표
- 텍스트 데이터 전처리의 중요성을 이해한다.
- 텍스트 데이터 전처리를 통해 노이즈를 줄이고 정보를 정리할 수 있는 방법을 배운다.
- 간단한 텍스트 정규화와 클리닝을 실습한다.
텍스트 데이터를 정리하고 깨끗하게!
텍스트 데이터는 우리가 일상에서 접하는 이메일, 리뷰, 소셜 미디어 게시글, 뉴스 기사 등 다양한 형태로 존재하며, 세상에서 가장 흔히 볼 수 있는 비정형 데이터 중 하나이다. 이 데이터는 단순한 숫자나 표와 달리 사람들이 실제로 사용하는 언어를 담고 있어, 이를 분석하면 소비자 감정, 사회적 트렌드, 혹은 기술적인 지식까지도 파악할 수 있는 무궁무진한 가능성을 제공한다. 하지만 텍스트 데이터는 그 복잡성과 노이즈 때문에 분석하기 까다로운 데이터로도 유명하다. 과연 어떻게 방대한 양의 텍스트 속에서 의미 있는 정보를 추출할 수 있을까? 이번 장에서는 텍스트 데이터를 다루는 기본적인 전처리 기법부터, 이 데이터를 수치로 변환하여 분석 가능한 형태로 만드는 과정까지 흥미로운 여정을 함께할 것이다. 텍스트 데이터를 탐구하며 데이터가 가진 숨은 이야기를 발견해보자!
1. 텍스트 데이터 알아보기
텍스트 데이터는 비정형 데이터(Structured Data가 아닌 데이터)의 대표적인 예로, 정형 데이터와는 다른 고유한 특성과 처리상의 도전 과제를 가진다.
1.1 텍스트 데이터의 특성
비정형 데이터 : 구조화되지 않음
텍스트 데이터는 숫자나 표와 같은 정형 데이터와 달리 일정한 구조를 가지지 않는 비정형 데이터이다. 예를 들어, 이메일, 문서, 소셜 미디어 게시글, 리뷰 등 다양한 형태로 존재한다. 또한, 텍스트 데이터는 문장, 단어, 문자뿐만 아니라 기호와 이모지와 같은 다양한 형식으로 구성되어 있다.
고차원 데이터 : 단어의 조합이 다양함
또한, 텍스트 데이터를 분석하기 위해 수치화(예: 벡터화)하면, 데이터의 대부분이 0으로 채워지는 희소 행렬(Sparse Matrix)의 형태를 띠게 된다. 이는 텍스트의 어휘가 많아질수록 특정 문서에 등장하지 않는 단어의 비율이 높아지기 때문이다. 예를 들어, 수천 개의 단어로 구성된 어휘에서 특정 문서가 사용하는 단어는 극히 일부에 불과하며, 나머지는 0으로 표현된다. 이러한 희소성은 텍스트 데이터 처리에서 중요한 고려사항으로, 모델링 성능과 계산 효율성에 큰 영향을 미친다.
노이즈가 많음 : 불필요한 정보 포함
텍스트 데이터에는 분석에 방해가 되는 불필요한 정보가 포함될 수 있다. 예를 들어, 이메일이나 웹페이지에서 수집한 텍스트 데이터에는 "지금 구매하세요!" 또는 "최대 50% 할인"과 같은 광고 문구가 포함될 수 있는데, 이러한 정보는 분석의 주요 대상이 아니므로 제거해야 한다. 또한, 동일한 리뷰나 댓글이 데이터셋에 여러 번 반복되어 나타나는 경우, 예를 들어 "이 제품 정말 좋아요!"와 같은 문장이 반복되면 데이터 분석 결과에 왜곡을 초래할 수 있다.
소셜 미디어 데이터에서는 철자 오류나 불완전한 문장이 자주 발견된다. 예를 들어, "Teh best prduct"처럼 오타가 포함되거나, "이게... 최고야!!"처럼 불완전한 문장은 분석의 정확성을 저하시킬 수 있다. 더불어 텍스트에는 특수문자와 이모지가 포함될 수 있는데, 특수문자인 @, #, % 등은 맥락에 따라 불필요한 요소가 될 수도 있다. 예를 들어, "#Python"과 같은 해시태그는 소셜 미디어 분석에서는 유용하지만, 일반적인 텍스트 분석에서는 제거해야 할 수 있다.
또한, 이모티콘과 이모지는 텍스트에서 감정을 표현하거나 강조하기 위해 사용되며, "이 제품 정말 좋아요! 😊👍"처럼 긍정적인 감정을 나타낼 수 있다. 하지만 기계 학습 모델에서 이를 다루기 위해서는 추가적인 전처리가 필요하다. 따라서 이러한 불필요한 정보들은 전처리 과정에서 제거하거나 적절히 처리하여 분석의 정확도를 높여야 하며, 이를 위해 정규 표현식이나 텍스트 정제 기법과 같은 도구를 활용할 수 있다.
문맥 의존성 : 단어의 의미가 문맥에 따라 달라짐
텍스트 데이터에서 단어의 의미는 문맥에 따라 달라지기 때문에 정확한 해석을 위해 문맥을 고려하는 것이 중요하다. 예를 들어, 단어 "bank"는 문장에 따라 "강가"를 의미할 수도 있고 "은행"을 뜻할 수도 있다. "The bank of the river"라는 문맥에서는 "강가"를 나타내지만, "I need to visit the bank"라는 문맥에서는 "은행"을 의미한다. 이처럼 동일한 단어라도 주변 단어와 문맥에 따라 다른 의미로 해석될 수 있기 때문에 자연어 처리에서는 문맥을 고려한 분석이 필수적이다.
또한, 단어의 순서 역시 텍스트의 의미를 결정하는 중요한 요소이다. 예를 들어, "The cat chased the dog"와 "The dog chased the cat"은 단어 구성은 같지만 단어의 순서가 다르기 때문에 전혀 다른 의미를 가진다. 단어의 순서를 무시하면 텍스트의 중요한 의미를 잃을 수 있기 때문에 이를 처리하는 과정에서는 문장의 구조와 단어 순서에 대한 정보도 함께 반영되어야 한다. 이러한 특징은 텍스트 데이터를 처리할 때 단순한 단어 빈도 분석을 넘어 문맥과 순서 정보를 활용할 수 있는 모델, 예를 들어 Word2Vec, BERT와 같은 임베딩 기법이나 순환 신경망(RNN) 등의 필요성을 강조한다.
다국어 및 지역성 : 언어의 다양성
언어의 다양성은 텍스트 데이터를 처리할 때 중요한 도전 과제 중 하나이다. 각 언어는 고유한 문법, 어휘, 표현 방식을 가지고 있어, 언어마다 서로 다른 처리 방식이 필요하다. 예를 들어, 영어는 주로 띄어쓰기를 기준으로 단어를 구분하지만, 중국어나 일본어는 띄어쓰기가 없기 때문에 별도의 토큰화 기법이 필요하다. 또한, 언어마다 단어의 형태가 변화하는 방식이나 문법 규칙이 다르기 때문에 다국어 데이터를 분석할 경우, 각 언어에 맞는 전처리 방법과 모델링이 요구된다.
더불어, 텍스트 데이터에는 특정 지역적 특성이 반영될 수 있다. 슬랭, 방언, 약어, 이모티콘 등은 텍스트에 나타나는 문화적 요소로, 이는 같은 언어를 사용하는 사용자 간에도 해석에 차이를 유발할 수 있다. 예를 들어, 영어에서는 "LOL"이 "Laugh Out Loud"의 약어로 사용되지만, 이는 특정 맥락에서만 이해될 수 있다. 한국어에서는 지역에 따라 "사투리"가 포함된 문장이 나타날 수 있으며, 이모티콘이나 이모지 또한 각 문화권에서 다르게 사용될 수 있다. 이러한 다양성과 지역적 특성은 텍스트 데이터를 처리할 때 단순한 언어 처리를 넘어, 해당 텍스트의 문화적 배경과 맥락을 고려한 접근이 필요함을 의미한다.
데이터 크기 : 대량의 데이터
텍스트 데이터는 한 번에 대량으로 수집되는 경우가 많아, 이를 효율적으로 저장하고 처리하는 것이 중요한 과제가 된다. 예를 들어, 소셜 미디어 플랫폼에서는 하루에도 수백만 개의 트윗과 댓글이 생성되며, 이를 실시간으로 분석하거나 저장하려면 고도의 데이터 처리 능력이 필요하다. 대규모 텍스트 데이터를 다루기 위해서는 분산 처리 시스템(예: Hadoop, Spark)이나 스트리밍 데이터 처리 기술이 자주 사용된다.
또한, 텍스트 데이터의 길이에 따라 처리 방식이 달라질 수 있다. 논문, 기사와 같이 긴 텍스트는 주제별 요약이나 주요 정보 추출에 중점을 두며, 문단 간 관계를 파악하거나 핵심 문장을 선정하는 작업이 필요하다. 반면, 트윗이나 리뷰처럼 짧은 텍스트는 단어의 빈도나 감정 분석에 적합하며, 간결한 문장에서 의미를 빠르게 파악하는 데 초점을 맞춘다. 예를 들어, 긴 텍스트에서는 문단 단위의 의미 흐름을 이해하기 위해 LSTM이나 Transformer 모델이 유용할 수 있고, 짧은 텍스트에서는 단순한 TF-IDF 또는 워드 임베딩 기반 분석으로도 충분할 수 있다. 이러한 차이를 인지하고 데이터 특성에 맞는 방법을 적용하는 것이 텍스트 데이터 처리의 핵심이다.
표현 및 변환 필요성 : 수치 데이터로 변환 필요
텍스트 데이터는 자연어로 구성되어 있어 기계 학습 모델에서 직접 활용할 수 없으므로, 이를 벡터나 행렬 형태의 수치 데이터로 변환하는 과정이 필수적이다. 대표적인 방법으로는 TF-IDF(Term Frequency-Inverse Document Frequency), Word2Vec, BERT 등이 있다. TF-IDF는 단어의 빈도와 중요도를 반영하여 문서를 벡터로 변환하며, 주로 텍스트의 전반적인 특성을 파악하는 데 사용된다. Word2Vec은 단어를 저차원 벡터로 임베딩하여 단어 간 의미적 유사성을 반영하는 데 효과적이고, BERT는 문맥을 고려한 정교한 언어 모델로 문장 단위의 복잡한 의미를 캡처할 수 있다.
이러한 변환을 하기 전에는 다양한 전처리 기법을 적용해야 한다. 예를 들어, 데이터에서 특수문자와 불필요한 기호를 제거하고, 단어를 일관성 있게 소문자로 변환하거나, 문장을 토큰화하여 단어 단위로 분리하는 작업이 필요하다. 또한, "running"과 "run"처럼 형태가 다른 단어를 같은 의미로 간주하기 위해 표제어 추출(Lemmatization)이나 어간 추출(Stemming)을 수행할 수 있다. 이러한 전처리 과정은 텍스트 데이터의 노이즈를 줄이고, 변환된 수치 데이터가 더 정확하고 효과적으로 모델링에 활용될 수 있도록 돕는다. 예를 들어, 소셜 미디어에서 수집한 리뷰 데이터를 분석할 때는, "좋아요!!!" 같은 문장에서 불필요한 느낌표를 제거하고 "좋다"로 정규화한 후, 이를 TF-IDF로 변환하여 소비자 의견의 패턴을 분석할 수 있다.
이러한 특징 때문에 텍스트 데이터는 데이터 분석 및 머신러닝에서 다루기 까다롭지만, 제대로 처리할 경우 매우 풍부한 정보를 제공하는 데이터 소스가 된다.
1.2 주요 텍스트 전처리 단계
Step1. 토큰화(Tokenization)
토큰화는 텍스트를 작은 단위로 나누는 과정으로, 단어 단위, 문장 단위 등 다양한 방식으로 분리할 수 있다.
- 단어 단위 토큰화: 텍스트를 단어별로 나누어 분석 가능한 최소 단위로 만든다.
예를 들어, "I love Python programming"이라는 문장은 ['I', 'love', 'Python', 'programming']으로 나뉜다. - word_tokenize는 NLTK 라이브러리의 punkt 리소스를 필요로 합니다. 먼저 punkt를 다운로드했는지 확인하세요.
- 영어 문장 토큰화를 위한 사전 훈련된 Punkt 모델이 포함된 punkt를 다운로도 해야합니다. 이 모델은 단어를 토큰화하기 전에 문장 경계를 식별하는 데 필수적입니다. 이 모델이 없으면 word_tokenize 함수가 제대로 작동할 수 없습니다.
- 문장 단위 토큰화: 텍스트를 문장별로 나눈다. 예를 들어, "Python is amazing. I love coding."은 ['Python is amazing.', 'I love coding.']으로 분리된다.
토큰화는 데이터 분석에서 기본 중의 기본 작업으로, NLTK, spaCy 등의 라이브러리를 사용해 쉽게 수행할 수 있다.
from nltk.tokenize import sent_tokenize
import nltk
# 필요한 리소스 다운로드
nltk.download('punkt')
# 샘플 텍스트 데이터
texts = "Python is amazing. I love coding! Do you like programming?"
# 문장 단위로 토큰화
sentences = sent_tokenize(texts)
print(sentences)
Step2. 불용어 제거(Stopword Removal)
불용어는 "the", "is", "in"과 같이 분석에 큰 의미가 없는 단어를 말한다. 이러한 단어들은 데이터 분석에 불필요한 노이즈를 증가시킬 수 있다.
- 예를 들어, "I love programming in Python"이라는 문장에서 불용어 "I", "in"을 제거하면 ['love', 'programming', 'Python']만 남게 된다.
NLTK와 같은 라이브러리는 미리 정의된 불용어 목록을 제공하며, 분석 대상에 맞게 목록을 수정할 수도 있다.
pip install nltk
- NLTK에는 다양한 언어의 불용어 목록이 포함되어 있으며, 이를 stopwords 모듈에서 확인할 수 있다.
- NLTK는 여러 언어의 불용어 목록을 제공한다.
- NLTK에는 한국어 불용어 목록을 기본 제공되지 않는다.
import nltk
from nltk.corpus import stopwords
# 필요한 데이터 다운로드
nltk.download('stopwords')
# 영어 불용어 목록 확인
english_stopwords = stopwords.words('english')
print(english_stopwords)
['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', "you're", "you've", "you'll", "you'd", 'your', 'yours', 'yourself', 'yourselves', 'he', 'him', 'his', 'himself', 'she', "she's", 'her', 'hers', 'herself', 'it', "it's", 'its', 'itself', 'they', 'them', 'their', 'theirs', 'themselves', 'what', 'which', 'who', 'whom', 'this', 'that', "that'll", 'these', 'those', 'am', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had', 'having', 'do', 'does', 'did', 'doing', 'a', 'an', 'the', 'and', 'but', 'if', 'or', 'because', 'as', 'until', 'while', 'of', 'at', 'by', 'for', 'with', 'about', 'against', 'between', 'into', 'through', 'during', 'before', 'after', 'above', 'below', 'to', 'from', 'up', 'down', 'in', 'out', 'on', 'off', 'over', 'under', 'again', 'further', 'then', 'once', 'here', 'there', 'when', 'where', 'why', 'how', 'all', 'any', 'both', 'each', 'few', 'more', 'most', 'other', 'some', 'such', 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too', 'very', 's', 't', 'can', 'will', 'just', 'don', "don't", 'should', "should've", 'now', 'd', 'll', 'm', 'o', 're', 've', 'y', 'ain', 'aren', "aren't", 'couldn', "couldn't", 'didn', "didn't", 'doesn', "doesn't", 'hadn', "hadn't", 'hasn', "hasn't", 'haven', "haven't", 'isn', "isn't", 'ma', 'mightn', "mightn't", 'mustn', "mustn't", 'needn', "needn't", 'shan', "shan't", 'shouldn', "shouldn't", 'wasn', "wasn't", 'weren', "weren't", 'won', "won't", 'wouldn', "wouldn't"]
[nltk_data] Downloading package stopwords to /root/nltk_data...
[nltk_data] Package stopwords is already up-to-date!
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
import nltk
# 필요한 리소스 다운로드
nltk.download('stopwords')
nltk.download('punkt')
# 샘플 텍스트 데이터
text = "I love programming in Python. It's amazing to work on data science projects."
# 1. 텍스트 토큰화
tokens = word_tokenize(text)
# 2. 불용어 목록 가져오기
stop_words = set(stopwords.words('english'))
# 3. 불용어 제거 (대소문자 구분 유지)
# filtered_tokens = [word for word in tokens if word not in stop_words] #간결한 리스트 내포 문법 형식
filtered_tokens = []
for word in tokens:
if word not in stop_words: # 조건: word가 불용어 목록에 없으면
filtered_tokens.append(word) # 리스트에 추가
# 결과 출력
print("Original Tokens:", tokens)
print("Filtered Tokens:", filtered_tokens)
- word = 'I' → 'I' in stop_words → True → 포함하지 않음
- word = 'love' → 'love' in stop_words → False → 리스트에 추가
Original Tokens: ['I', 'love', 'programming', 'in', 'Python', '.', 'It', "'s", 'amazing', 'to', 'work', 'on', 'data', 'science', 'projects', '.']
Filtered Tokens: ['I', 'love', 'programming', 'Python', '.', 'It', "'s", 'amazing', 'work', 'data', 'science', 'projects', '.']
Step3. 소문자 변환 및 정규화
소문자 변환은 텍스트 데이터의 일관성을 유지하고, 분석 효율성을 높이기 위해 대문자를 소문자로 변환하는 작업이다.
- 소문자 변환 : 텍스트 데이터는 대소문자를 구분하기 때문에 동일한 의미를 가진 단어라도 대문자와 소문자가 섞여 있으면 서로 다른 단어로 인식된다.
- 예를 들어, "Python", "PYTHON", "python"은 동일한 단어지만 분석 시스템에서는 서로 다르게 취급할 수 있다.
- 이 작업은 간단하지만, 텍스트 분석의 정확도를 높이는 데 중요한 역할을 한다. 특히 영어처럼 대소문자를 구분하는 언어에서 매우 유용하다.
text = "Python is Amazing"
lower_text = text.lower()
print(lower_text)
- 정규화(Normalization): 정규화는 텍스트 데이터의 변동성을 줄이고 의미를 통합하기 위해 비슷한 의미를 가진 단어들을 일관된 형태로 변환하는 과정이다.
- 예를 들어, "run", "running", "runs"는 기본적으로 같은 동작을 나타내지만, 형태가 다르기 때문에 서로 다른 단어로 처리될 수 있다.
- 정규화를 통해 이러한 단어를 공통된 형태로 변환하면, 데이터의 복잡성을 줄이고 분석의 효율성을 높일 수 있다.
Step4. 어간 추출(Stemming) 및 표제어 추출(Lemmatization)
이 과정은 단어를 기본 형태로 변환하여 어휘의 다양성을 줄이는 작업이다.
- 어간 추출(Stemming): 단어의 어간(Stem)을 추출하는 방법으로, 규칙 기반으로 단어의 접미사 등을 제거한다.
- 예: "running", "runner" → "run".
# NLTK에서 제공하는 PorterStemmer 클래스를 가져옵니다.
from nltk.stem import PorterStemmer
# PorterStemmer 객체를 생성합니다.
stemmer = PorterStemmer()
# 어간 추출을 수행할 단어를 정의합니다.
word = 'running'
# 'running' 단어의 어간을 추출합니다.
stemmed_word = stemmer.stem(word)
# 추출된 어간을 출력합니다.
print(stemmed_word) # 출력 결과: 'run'
- 표제어 추출(Lemmatization): 문맥과 문법 정보를 활용해 단어를 사전에 존재하는 기본 형태로 변환한다. 예: "am", "are", "is" → "be".
표제어 추출은 문맥 정보를 활용하므로 더 정교한 변환이 가능하다. spaCy나 NLTK에서 활용할 수 있다.
# NLTK 라이브러리 임포트
import nltk
# WordNetLemmatizer 클래스 가져오기
from nltk.stem import WordNetLemmatizer
# WordNet 리소스 다운로드 (표제어 추출에 필요)
nltk.download('wordnet')
# WordNetLemmatizer 객체 생성
lemmatizer = WordNetLemmatizer()
# 표제어 추출을 수행할 단어 정의
word = 'am'
# 'am' 단어를 동사(pos='v')로 간주하여 표제어를 추출
lemma = lemmatizer.lemmatize(word, pos='v')
# 추출된 표제어 출력
print(lemma) # 출력 결과: 'be'
왜 소문자 변환과 정규화가 중요한가?
- 중복 데이터 제거: "Python"과 "python"을 같은 단어로 처리하여 분석의 일관성을 유지한다.
- 어휘 크기 축소: 정규화를 통해 "run", "running", "runs"를 모두 "run"으로 처리하면 어휘의 크기를 줄여 모델이 더 적은 데이터로 학습할 수 있다.
- 효율성 향상: 단어의 변형을 줄이면 계산량이 감소하고, 모델 성능이 개선된다.
Step5. 특수문자 및 불필요한 기호 제거
텍스트에는 분석과 관련 없는 특수문자(예: @, #, !, ?)와 기호가 포함될 수 있다.
- 예를 들어, "I love Python! :) #coding"이라는 문장에서 특수문자와 기호를 제거하면 "I love Python coding"이 된다.
정규 표현식(Regular Expressions)을 활용하면 이러한 기호들을 자동으로 탐지하고 제거할 수 있다.
import re
# 샘플 텍스트
text = "I love Python! :) #coding"
# 특수문자 및 불필요한 기호 제거
cleaned_text = re.sub(r"[^a-zA-Z\s]", "", text)
# 결과 출력
print("Original Text:", text)
print("Cleaned Text:", cleaned_text)
이러한 전처리 단계는 데이터의 노이즈를 줄이고, 모델이 텍스트의 중요한 정보에 집중하도록 돕는다. 초보자도 Python 라이브러리를 활용해 간단히 적용할 수 있으니 차근차근 연습하며 익혀보길 추천한다. 😊
1.3. 텍스트 데이터 전처리 라이브러리
- NLTK (Natural Language Toolkit)
- NLTK는 자연어 처리를 위한 Python의 전통적인 라이브러리로, 자연어 처리에 필요한 방대한 기능과 데이터를 제공한다.
- 다양한 텍스트 처리 도구: 토큰화(Tokenization), 품사 태깅(Part-of-Speech Tagging), 개체명 인식(Named Entity Recognition), 구문 분석(Parsing) 등 거의 모든 NLP 작업을 지원한다.
- 방대한 말뭉치(Corpus): 영어 불용어 목록, 브라운 말뭉치(Brown Corpus), 워드넷(WordNet) 등 다양한 언어 자료를 제공한다.
- 교육 및 학습용 적합: 초보자가 NLP 개념을 이해하고 학습하는 데 적합하며, 사용법이 비교적 직관적이다.
- spaCy: 빠르고 효율적인 NLP 라이브러리.
- spaCy는 빠르고 효율적인 현대적인 NLP 라이브러리로, 대규모 텍스트 데이터 처리와 실시간 응용 프로그램에 적합하다.
- 빠른 처리 속도: Cython으로 작성되어 대규모 데이터와 실시간 처리를 빠르게 수행할 수 있다.
- 현대적 기능: 최신 모델(Transformer, BERT)과의 통합, 문맥 기반 분석 지원.
- 사전 학습된 모델: 다양한 언어의 사전 학습된 모델을 제공하여 품사 태깅, 개체명 인식, 의존 구문 분석 등을 쉽게 수행 가능.
- 사용자 친화적 API: 간결한 코드로 복잡한 작업 수행.
- re: 정규 표현식을 활용한 텍스트 처리.
- re는 Python 내장 모듈로, 텍스트 데이터에서 특정 패턴을 탐색, 매칭, 변환하는 데 사용된다.
- 간단하고 가벼운 텍스트 처리 작업에 적합.
- 정규 표현식을 통해 특정 문자, 단어, 패턴 등을 탐색하거나 변환 가능.
import re # 정규 표현식을 사용하기 위한 re 모듈 임포트
# 샘플 텍스트
text = "This is a test sentence with numbers: 123 and special characters: @#."
# 숫자 제거: \d+는 숫자(0-9)를 의미하며, 이를 빈 문자열("")로 대체
text_no_numbers = re.sub(r"\d+", "", text)
print(text_no_numbers) # "This is a test sentence with numbers: and special characters: @#."
# 특수문자 제거: [^a-zA-Z\s]는 알파벳(a-z, A-Z)와 공백(\s)을 제외한 모든 문자를 탐지
# 탐지된 문자를 빈 문자열("")로 대체하여 제거
text_cleaned = re.sub(r"[^a-zA-Z\s]", "", text)
print(text_cleaned)
세 라이브러리 비교
라이브러리 | 주요 용도 | 장점 | 단점 |
NLTK | 교육 및 연구용 NLP | 방대한 말뭉치와 NLP 도구 제공 | 느리고 대규모 데이터에 비효율 |
spaCy | 대규모 데이터 및 실시간 NLP | 빠르고 현대적, 최신 모델과 호환 | 초보자에게 진입 장벽 존재 |
re | 정규 표현식을 활용한 간단한 텍스트 처리 | 가볍고 빠르며 설치 불필요 | 복잡한 NLP 작업에 부적합 |
2. 정규 표현식을 활용한 텍스트 처리
Python의 내장 모듈 re는 정규 표현식(Regular Expression)을 사용하여 텍스트 데이터를 검색, 매칭, 변환하는 데 강력한 도구를 제공한다. 정규 표현식은 특정 패턴을 정의하여 텍스트 내에서 원하는 데이터를 추출하거나, 불필요한 데이터를 제거하는 데 유용하다. 이러한 특성 덕분에 데이터 전처리와 간단한 텍스트 분석 작업에서 매우 널리 사용된다.
2.1 정규 표현식의 주요 활용 사례
- 패턴 검색 : 텍스트에서 특정 형식을 가진 데이터(예: 이메일 주소, 전화번호, 날짜 등)를 검색할 수 있다.
예: re.search를 사용하여 이메일 주소를 텍스트에서 추출. - 텍스트 변환 : 불필요한 문자나 기호를 제거하거나, 특정 패턴을 다른 형태로 변환할 수 있다.
예: 숫자 제거, 특수문자 제거. - 데이터 정제 : 텍스트 데이터를 일관된 형태로 정리하여 분석에 적합한 상태로 만드는 데 사용된다.
예: 공백 정리, 중복 문자 제거.
2.2 정규 표현식의 주요 함수
re.search(pattern, string)
- 문자열에서 첫 번째 매칭되는 패턴을 검색.
- 매칭된 객체 반환(없으면 None).
import re
text = "My email is example@gmail.com"
match = re.search(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", text)
if match:
print(match.group()) # example@gmail.com
- 이메일 형식: 로컬 파트 + @ + 도메인 이름 + . + 최상위 도메인
- [a-zA-Z0-9._%+-]: 알파벳(대소문자), 숫자, 점(.), 밑줄(_), 퍼센트(%), 더하기(+), 빼기(-)로 구성된 로컬 파트(이메일 주소의 @ 앞부분).
- [a-zA-Z0-9.-] : 알파벳(대소문자), 숫자, 점(.), 하이픈(-)으로 구성된 도메인 이름.
- \. : 도메인과 최상위 도메인(TLD)을 구분하는 점.
- [a-zA-Z]{2,} : 최소 2자 이상의 알파벳으로 구성된 최상위 도메인(예: com, org).
re.findall(pattern, string)
- 문자열r에서 모든 매칭되는 패턴을 리스트로 반환.
text = "Contact us at info@test.com and support@company.org"
emails = re.findall(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", text)
print(emails) # ['info@test.com', 'support@company.org']
re.sub(pattern, replacement, string)
- 패턴에 매칭되는 부분을 특정 문자열로 치환.
text = "Price is $100 and $200"
result = re.sub(r"\$\d+", "XXX", text)
print(result) # "Price is XXX and XXX"
re.split(pattern, string)
- 패턴을 기준으로 문자열을 분리.
text = "apple,banana;grape|orange"
result = re.split(r"[,;|]", text)
print(result) # ['apple', 'banana', 'grape', 'orange']
2.3 정규 표현식의 주요 패턴
패턴 | 설명 | 예시 |
. | 임의의 문자(개행 제외) | a.c → abc, aXc |
\d | 숫자 | \d+ → 123, 45 |
\w | 알파벳 + 숫자 + 밑줄(_) | \w+ → abc123, _test |
\s | 공백 문자 | \s+ → 공백, 탭, 줄바꿈 |
^ | 문자열 시작 | ^hello → hello world |
$ | 문자열 끝 | world$ → hello world |
* | 0회 이상 반복 | a* → aaa, a, `` |
+ | 1회 이상 반복 | a+ → aaa, a |
{n,m} | n~m회 반복 | a{2,3} → aa, aaa |
[abc] | 괄호 안의 문자 중 하나와 매칭 | [abc] → a, b, c |
[^abc] | 괄호 안의 문자 제외 | [^abc] → x, y |
` | ` | OR 연산 |
이메일 | [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,} |
연습문제
문제1) 특정 패턴 추출 : 주어진 문자열에서 이메일 주소를 모두 추출하는 정규 표현식을 작성하시오.
- 참고 : 이메일 형식 - [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
import re
text = "Contact us at support@example.com or sales@company.org for more information."
# 정규 표현식을 작성하여 이메일 주소 추출
emails = re.findall(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", text)
print(emails)
문제2) 특수문자 제거 : 주어진 문자열에서 알파벳과 공백만 남기고 나머지 모든 문자(숫자, 특수문자)를 제거하는 정규 표현식을 작성하시오.
import re
text = "Hello, World! It's 2025. Welcome to NLP :)"
# 정규 표현식을 작성하여 특수문자와 숫자를 제거
cleaned_text = re.sub(r"[^a-zA-Z\s]", "", text)
print(cleaned_text)
문제3) 숫자 추출 : 주어진 문자열에서 숫자만 추출하는 정규 표현식을 작성하시오.
import re
text = "Order numbers: 12345, 67890, and reference code 202501."
# 정규 표현식을 작성하여 숫자만 추출
numbers = re.findall(r"\d+", text)
print(numbers)
['12345', '67890', '202501']
2. 텍스트 데이터 전처리 따라 해 보기
예제1)
# 샘플 텍스트 데이터
texts = [
"I love NLP and Text Mining!",
"Data Science is amazing; isn't it?",
"Python is widely used for Machine Learning."
]
토큰화
from nltk.tokenize import word_tokenize
import nltk
# 필요한 리소스 다운로드
nltk.download('punkt')
texts = [
"I love NLP and Text Mining!",
"Data Science is amazing; isn't it?",
"Python is widely used for Machine Learning."
]
for text in texts:
print(word_tokenize(text))
['I', 'love', 'NLP', 'and', 'Text', 'Mining', '!']
['Data', 'Science', 'is', 'amazing', ';', 'is', "n't", 'it', '?']
['Python', 'is', 'widely', 'used', 'for', 'Machine', 'Learning', '.']
불용어 제거
from nltk.corpus import stopwords
import nltk
# 필요한 리소스 다운로드
nltk.download('punkt')
# Download the stopwords dataset
nltk.download('stopwords') # This line downloads the necessary stopwords dataset.
texts = [
"I love NLP and Text Mining!",
"Data Science is amazing; isn't it?",
"Python is widely used for Machine Learning."
]
stop_words = set(stopwords.words('english'))
for text in texts:
words = word_tokenize(text)
filtered_words = [w for w in words if w.lower() not in stop_words]
print(filtered_words)
['love', 'NLP', 'Text', 'Mining', '!']
['Data', 'Science', 'amazing', ';', "n't", '?']
['Python', 'widely', 'used', 'Machine', 'Learning', '.']
소문자 변환 및 정규화
import re
for text in filtered_words:
clean_text = re.sub(r"[^a-zA-Z]", " ", text).lower()
print(clean_text)
python
widely
used
machine
learning
예제2)
아래는 간단한 텍스트 데이터셋을 사용하여 전처리를 수행하는 완전한 Python 코드이다. 데이터셋은 임의로 생성한 리스트로 구성되어 있으며, 불필요한 기호 및 숫자 제거, 불용어 처리, 어간 추출을 포함한다. 이를 데이터프레임으로 저장하여 출력하는 작업까지 포함된다.
# 필요한 라이브러리 설치 및 임포트
import pandas as pd
import re
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer
import nltk
# 필요한 데이터 다운로드
nltk.download('stopwords')
# 1. 간단한 텍스트 데이터셋 생성
data = {
"text": [
"I love programming with Python! 😊👍",
"This is an example of text preprocessing. #NLP",
"123 numbers and @special #characters should be removed!",
"NLTK is great for natural language processing."
]
}
# 데이터셋을 데이터프레임으로 변환
df = pd.DataFrame(data)
# 2. 불필요한 기호 및 숫자 제거
def clean_text(text):
text = re.sub(r"[^a-zA-Z\s]", "", text) # 알파벳과 공백만 남김
text = re.sub(r"\s+", " ", text) # 연속된 공백 제거
text = text.strip() # 앞뒤 공백 제거
return text
df['cleaned_text'] = df['text'].apply(clean_text)
# 3. 불용어 제거
stop_words = set(stopwords.words('english'))
def remove_stopwords(text):
words = text.split()
filtered_words = [word for word in words if word.lower() not in stop_words]
return " ".join(filtered_words)
df['no_stopwords'] = df['cleaned_text'].apply(remove_stopwords)
# 4. 어간 추출(Stemming)
stemmer = PorterStemmer()
def stem_words(text):
words = text.split()
stemmed_words = [stemmer.stem(word) for word in words]
return " ".join(stemmed_words)
df['stemmed_text'] = df['no_stopwords'].apply(stem_words)
# 5. 결과 출력
print("전처리 결과:")
print(df)
# 결과를 CSV 파일로 저장 (옵션)
df.to_csv("preprocessed_text.csv", index=False)
- 텍스트 데이터셋 생성 : 간단한 텍스트 데이터를 딕셔너리 형태로 생성한 후, 데이터프레임으로 변환.
- 불필요한 기호 및 숫자 제거 : re.sub를 사용하여 알파벳과 공백 이외의 문자(숫자, 특수문자 등)를 제거.
- 불용어 제거 : NLTK에서 제공하는 영어 불용어 목록을 사용하여 텍스트에서 의미 없는 단어를 제거.
- 어간 추출(Stemming) : NLTK의 PorterStemmer를 사용하여 단어를 어간으로 변환.
- 결과 출력 및 저장 : 전처리 결과를 데이터프레임으로 출력하며, 필요 시 CSV 파일로 저장.\
3. 도전 해 보기
과제1: 초능력 감정 분석 비서 만들기! ( spaCy )
여러분은 "초능력 감정 분석 비서"를 만드는 데이터 과학자입니다. 이 비서는 사람들이 작성한 리뷰나 문장을 읽고, 긍정적 감정(😊)과 부정적 감정(😡)을 찾아냅니다. 여러분의 임무는 아래와 같은 기능을 사용하여 기본적인 감정 분석 작업을 수행하는 것입니다.
주어진 텍스트에서 다음 작업을 수행하시오:
- 텍스트 토큰화
문장을 단어 단위로 나누고, 각 단어를 출력하시오. - 품사 태깅
단어별 품사를 분석하고, 명사(NOUN)와 동사(VERB)만 출력하시오. - 감정 단어 찾기
긍정적인 단어(예: "love", "amazing", "great")와 부정적인 단어(예: "hate", "terrible", "bad")를 감지하고, 해당 단어와 위치를 출력하시오.
예제 텍스트
"I absolutely love this product! It's amazing and great for daily use. However, the delivery was terrible, and I hate the packaging."
spaCy를 설치하고 모델 로드하기
pip install spacy
python -m spacy download en_core_web_sm
필요한 라이브러리와 데이터 로드
import spacy
nlp = spacy.load("en_core_web_sm")
text = "I absolutely love this product! It's amazing and great for daily use. However, the delivery was terrible, and I hate the packaging."
doc = nlp(text)
- 토큰화: for token in doc: print(token.text)
- 품사 태깅: for token in doc: print(token.text, token.pos_)
- 긍정/부정 단어 감지
positive_words = ["love", "amazing", "great"]
negative_words = ["hate", "terrible", "bad"]
for token in doc:
if token.text.lower() in positive_words:
print(f"Positive word: {token.text} at position {token.i}")
elif token.text.lower() in negative_words:
print(f"Negative word: {token.text} at position {token.i}")
import spacy
# spaCy 모델 로드
nlp = spacy.load("en_core_web_sm")
# 샘플 텍스트
text = "I love programming. It is amazing, but sometimes debugging can be terrible."
# 텍스트를 spaCy로 처리
doc = nlp(text)
# 긍정 및 부정 단어 리스트
positive_words = ["love", "amazing", "great"]
negative_words = ["hate", "terrible", "bad"]
# 초기 빈도 카운트
positive_count = 0
negative_count = 0
# 긍정 및 부정 단어 탐색 및 카운트
for token in doc:
if token.text.lower() in positive_words:
positive_count += 1
print(f"Positive word: {token.text} at position {token.i}")
elif token.text.lower() in negative_words:
negative_count += 1
print(f"Negative word: {token.text} at position {token.i}")
# 감정 점수 계산
sentiment_score = positive_count - negative_count
# 결과 출력
print("\n--- Sentiment Analysis Results ---")
print(f"Positive Words Count: {positive_count}")
print(f"Negative Words Count: {negative_count}")
print(f"Sentiment Score: {sentiment_score}")
if sentiment_score > 0:
print("Overall Sentiment: Positive 😊")
elif sentiment_score < 0:
print("Overall Sentiment: Negative 😞")
else:
print("Overall Sentiment: Neutral 😐")
- token.text.lower(): 대소문자 구분을 없애기 위해 소문자로 변환.
- in positive_words: 단어가 긍정 단어 리스트에 포함되어 있는지 확인.
- 결과 출력: 단어와 해당 단어의 위치(token.i)를 출력.
Positive word: love at position 1
Positive word: amazing at position 6
Negative word: terrible at position 13
--- Sentiment Analysis Results ---
Positive Words Count: 2
Negative Words Count: 1
Sentiment Score: 1
Overall Sentiment: Positive 😊
이 텍스트에서 "love"와 "amazing" 같은 긍정적인 단어가 두 번 등장한 반면, "terrible"이라는 부정적인 단어는 한 번만 등장했습니다. 따라서 감정 점수는 +1로, 전반적으로 이 텍스트는 긍정적인 감정을 전달하고 있습니다. 프로그래밍은 사랑받고 즐거운 활동으로 묘사되지만, 디버깅과 같은 특정 과정은 때때로 좌절감을 줄 수 있음을 보여줍니다. 초보자에게는 "프로그래밍은 재미있지만 도전 과제가 있을 수도 있다"는 점을 알려주는 좋은 예시입니다. 이처럼 단순한 분석만으로도 텍스트에서 숨겨진 감정을 찾아낼 수 있다는 점은 텍스트 마이닝의 흥미로운 매력입니다! 😊
어디에 더 활용 해 볼까?
- 감정 분석: 텍스트에서 긍정 및 부정적인 감정을 탐지.
- 의견 분석: 리뷰나 댓글에서 긍정적/부정적 표현을 자동으로 분류.
- 문맥 정보 확인: 단어가 등장한 위치를 통해 텍스트의 흐름 파악.
과제2 가수 X의 노래 가사 분석
좋아하는 가수 (레이디 가가)의 노래 " Always Remember Us This Way "곡을 활용해 텍스트 데이터를 분석하고, 단어 빈도, 감정 분석, 시각화를 통해 자연어 처리 기술을 익힙니다.
- 문제 요구 사항 및 작업 단계
- 데이터 준비
- 가수 X의 대표곡 3~5곡의 가사를 텍스트 데이터로 준비하세요.
- 가사를 불러와 데이터프레임으로 정리하세요. (곡 이름과 가사를 포함)
- 데이터 탐색 및 전처리
- 가사를 단어 단위로 토큰화하고, 특수문자와 불필요한 단어를 제거하세요.
- 불용어(예: "the", "and", "is" 등)를 제거하여 정리된 단어 목록을 만드세요.
- 단어 빈도 분석
- 가사에서 가장 자주 등장하는 단어를 찾아 상위 10개를 출력하세요.
- 상위 10개 단어의 빈도를 막대그래프로 시각화하세요.
- 감정 분석
- 긍정적인 단어와 부정적인 단어를 감정 사전을 기반으로 탐지하고, 각각의 비율을 계산하세요.
- 감정 분석 결과를 파이차트로 시각화하세요.
- 추가 도전 과제
- 특정 단어(예: "love", "heart")가 어떤 곡에서 가장 많이 등장하는지 확인하세요.
- 단어 구름(Word Cloud)을 생성하여 가사의 핵심 단어를 시각화하세요.
- 데이터 준비
import re
from collections import Counter
import matplotlib.pyplot as plt
from wordcloud import WordCloud
from nltk.corpus import stopwords
import nltk
# NLTK 불용어 다운로드
nltk.download('stopwords')
stop_words = set(stopwords.words('english'))
# 1. 데이터 준비
data = {
"song": ["Shallow", "Bad Romance", "Poker Face"],
"lyrics": [
"Tell me something, girl. Are you happy in this modern world?",
"I want your love and I want your revenge. You and me could write a bad romance.",
"Can't read my, can't read my, no, he can't read my poker face."
]
}
df = pd.DataFrame(data)
# 2. 데이터 전처리
def preprocess_lyrics(lyrics):
lyrics = re.sub(r"[^a-zA-Z\s]", "", lyrics) # 특수문자 제거
tokens = lyrics.lower().split() # 소문자로 변환 후 단어 분리
tokens = [word for word in tokens if word not in stop_words] # 불용어 제거
return tokens
df['tokens'] = df['lyrics'].apply(preprocess_lyrics)
# 3. 단어 빈도 분석
all_words = sum(df['tokens'], []) # 모든 단어를 하나의 리스트로 합침
word_counts = Counter(all_words)
top_words = word_counts.most_common(10)
print("Top Words:", top_words)
# 단어 빈도 막대그래프
words, counts = zip(*top_words)
plt.bar(words, counts)
plt.title("Top 10 Words in Lady Gaga's Lyrics")
plt.xlabel("Words")
plt.ylabel("Frequency")
plt.show()
# 4. 감정 분석
positive_words = ["love", "happy", "girl"]
negative_words = ["revenge", "cant", "bad"]
positive_count = sum(word_counts[word] for word in positive_words if word in word_counts)
negative_count = sum(word_counts[word] for word in negative_words if word in word_counts)
# 감정 분석 결과 시각화
plt.pie([positive_count, negative_count], labels=["Positive", "Negative"], autopct='%1.1f%%', startangle=90)
plt.title("Emotion Distribution in Lyrics")
plt.show()
# 5. 추가 과제: 워드클라우드 생성
wordcloud = WordCloud(width=800, height=400, background_color="white").generate(" ".join(all_words))
plt.figure(figsize=(10, 5))
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis("off")
plt.show()
# 특정 단어의 등장 곡 확인
specific_word = "love"
df['word_count'] = df['tokens'].apply(lambda x: x.count(specific_word))
print(df[['song', 'word_count']])
- 단어 빈도 막대그래프
- 가장 자주 등장한 단어의 빈도를 한눈에 확인 가능.
- 감정 분석 파이차트
- 긍정적 단어와 부정적 단어의 비율을 시각화.
- 워드클라우드
- 레이디 가가의 가사에서 가장 중요한 단어를 시각적으로 표현.
- 특정 단어의 등장 곡
- "love"와 같은 특정 단어가 어느 곡에서 가장 많이 등장했는지 확인 가능.
과제. "Let It Be 가사 속 'Let it be'는 몇 번 나올까?"
비틀즈의 명곡 "Let It Be"에는 제목과 동일한 문구가 반복적으로 등장합니다. 이번 과제에서는 노래 가사를 텍스트 데이터로 다루어 'Let it be'가 몇 번 등장하는지 자동으로 계산하는 과제를 수행합니다.
눈으로 세는 대신, 텍스트 전처리와 분석 과정을 활용하여 직접 계산하고, 우리가 배운 텍스트 처리 기술을 실습해 보세요!
1) 텍스트 데이터 준비 : "Let It Be"의 가사를 문자열로 준비합니다.
# "Let It Be" 가사
file_path = "/content/let_it_be.txt" # 가사 파일 경로
with open(file_path, 'r') as file:
lyrics = file.read()
2) 필요한 라이브러리와 데이터를 다운로드
- 이 과제에서는 "let it be"라는 특정 패턴을 찾는 것이 목적입니다. 이 작업은 정규 표현식으로 간단히 처리 가능합니다.
import re
3) 데이터 정제 및 전처리 : 가사에서 대소문자 차이를 없애기 위해 소문자 변환을 수행합니다.
# 1. 텍스트를 소문자로 변환
lyrics = lyrics.lower()
특수문자 제거를 통해 텍스트를 정리합니다.
# 2. 특수문자를 제거하고 공백 정리
cleaned_lyrics = re.sub(r"[^\w\s]", "", lyrics)
패턴 탐색 : "let it be"라는 단어 조합이 몇 번 등장했는지 빈도 계산을 통해 확인합니다.
정규 표현식에서 \b(단어 경계)를 사용해, 정확히 let it be라는 단어 조합만 찾도록 설정했습니다.
# 3. "let it be" 등장 횟수 계산
count = len(re.findall(r"\blet it be\b", cleaned_lyrics))
결과 출력
# 4. 결과 출력
print(f"'Let it be'는 총 {count}번 등장합니다.")
완성 코드
import re
# "Let It Be" 가사
file_path = "/content/let_it_be.txt" # 가사 파일 경로
with open(file_path, 'r') as file:
lyrics = file.read()
# 1. 텍스트를 소문자로 변환
lyrics = lyrics.lower()
# 2. 특수문자를 제거하고 공백 정리
cleaned_lyrics = re.sub(r"[^\w\s]", "", lyrics)
# 3. "let it be" 등장 횟수 계산
count = len(re.findall(r"\blet it be\b", cleaned_lyrics))
# 4. 결과 출력
print(f"'Let it be'는 총 {count}번 등장합니다.")
과제2. "Let It Be, 희망과 평온의 가사 속 감정은? 빈도와 감정으로 풀어보는 비틀즈 명곡!"
1. 필요한 라이브러리와 리소스를 부르자.
import re
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from collections import Counter
import nltk
import matplotlib.pyplot as plt
# 필요한 리소스 다운로드
nltk.download('stopwords')
nltk.download('punkt')
2. 데이터 준비 및 읽기
# "Let It Be" 가사
file_path = "/content/let_it_be.txt" # 가사 파일 경로
with open(file_path, 'r') as file:
lyrics = file.read()
3. 소문자 변환
lyrics = lyrics.lower()
when i find myself in times of trouble, mother mary comes to me
speaking words of wisdom, let it be
and in my hour of darkness she is standing right in front of me
speaking words of wisdom, let it be
4. 토큰화
tokens = word_tokenize(lyrics)
5. 특수문자 제거
tokens = [re.sub(r"[^\w']", "", token) for token in tokens if token.strip()]
[^\w\s]: 단어(\w) 문자(\s)와 공백을 제외한^ 모든 문자(즉, 특수문자와 기호)를 탐지해서 공백처리
when i find myself in times of trouble mother mary comes to me
speaking words of wisdom let it be
and in my hour of darkness she is standing right in front of me
speaking words of wisdom let it be
6. 불용어 제거 및 커스트마이징
NLTK의 기본 불용어 목록에 추가적으로 제거하고 싶은 단어(예: "let", "be")를 포함시키면 더 정확한 분석이 가능합니다.
# 불용어 제거 및 커스터마이징
stop_words = set(stopwords.words('english'))
custom_stop_words = {"let", "be"}
stop_words.update(custom_stop_words)
filtered_tokens = [token for token in tokens if token and token not in stop_words]
['find', 'times', 'trouble', 'mother', 'mary', 'comes', 'speaking', 'words', 'wisdom', 'let']
7. 단어빈도수 계산
# 5. 단어 빈도수 계산
word_counts = Counter(filtered_tokens)
Counter({'let': 36, 'words': 8, 'wisdom': 8, 'whisper': 5, 'speaking': 3, 'answer': 3, 'mother': 2, ...
8. 결과 출력 :
# 상위 10개 단어 추출
top_words = word_counts.most_common(10)
words, counts = zip(*top_words)
Word Counts (Top 10): [('let', 36), ('words', 8), ('wisdom', 8), ('whisper', 5), ('speaking', 3)]
9. 시각화
# 시각화
bars = plt.bar(words, counts, color='skyblue')
plt.title("Top 10 Most Frequent Words in 'Let It Be'", fontsize=16)
plt.xlabel("Words", fontsize=12)
plt.ylabel("Frequency", fontsize=12)
plt.xticks(rotation=45)
plt.show()
import re
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from collections import Counter
import nltk
import matplotlib.pyplot as plt
# Download necessary NLTK resources
nltk.download('stopwords')
nltk.download('punkt')
# Download 'punkt_tab' for tokenization
nltk.download('punkt_tab') # This line is added
# "Let It Be" 가사 파일 로드
file_path = "/content/let_it_be.txt"
with open(file_path, 'r') as file:
lyrics = file.read()
# 소문자 변환
lyrics = lyrics.lower()
# 토큰화
tokens = word_tokenize(lyrics)
# 특수 문자 제거
tokens = [re.sub(r"[^\w']", "", token) for token in tokens if token.strip()]
# 불용어 제거 및 커스터마이징
stop_words = set(stopwords.words('english'))
custom_stop_words = {"let", "be"}
stop_words.update(custom_stop_words)
filtered_tokens = [token for token in tokens if token and token not in stop_words]
# 단어 빈도 계산
word_counts = Counter(filtered_tokens)
# 상위 10개 단어 추출
top_words = word_counts.most_common(10)
words, counts = zip(*top_words)
# 시각화
bars = plt.bar(words, counts, color='skyblue')
plt.title("Top 10 Most Frequent Words in 'Let It Be'", fontsize=16)
plt.xlabel("Words", fontsize=12)
plt.ylabel("Frequency", fontsize=12)
plt.xticks(rotation=45)
plt.show()
import re
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from collections import Counter
import nltk
import matplotlib.pyplot as plt
# NLTK 리소스 다운로드
nltk.download('stopwords')
nltk.download('punkt')
# 0. "Let It Be" 가사 파일 로드
file_path = "/content/let_it_be.txt"
with open(file_path, 'r') as file:
lyrics = file.read()
# 1. 텍스트 토큰화 (단어 단위로 나누기)
tokens = word_tokenize(lyrics)
# 2. 모든 단어를 소문자로 변환
tokens = [token.lower() for token in tokens]
# 3. 특수문자 제거 및 정규화 (불필요한 기호 제거)
tokens = [re.sub(r"[^\w\s]", "", token) for token in tokens]
# 4. 불용어 제거 (의미 없는 단어 제거)
stop_words = set(stopwords.words('english'))
filtered_tokens = [token for token in tokens if token and token not in stop_words]
# 5. 단어 빈도수 계산 (가장 자주 등장한 단어 찾기)
word_counts = Counter(filtered_tokens)
# 6. 감정 단어 정의 (긍정/부정 단어 목록)
positive_words = ["love", "wisdom", "light", "music"]
negative_words = ["trouble", "darkness", "broken"]
# 감정 분석 수행 (긍정 단어와 부정 단어 개수 계산)
positive_count = sum(word_counts[word] for word in positive_words if word in word_counts)
negative_count = sum(word_counts[word] for word in negative_words if word in word_counts)
# 결과 출력
print("**단어 빈도 분석 결과 (상위 10개 단어):**")
for word, count in word_counts.most_common(10):
print(f"{word}: {count}")
print(f"\n**긍정 단어 개수:** {positive_count}")
print(f"**부정 단어 개수:** {negative_count}")
# 7. 단어 빈도수 시각화
top_words = word_counts.most_common(10)
words, counts = zip(*top_words)
plt.bar(words, counts) # 각 막대 색상 다르게
plt.title("Top 10 Most Frequent Words in 'Let It Be'")
plt.xlabel("Words")
plt.ylabel("Frequency")
plt.xticks(rotation=45)
plt.show()
# 8. 감정 분석 결과 시각화
plt.pie(
[positive_count, negative_count],
labels=["Positive", "Negative"],
autopct="%1.1f%%",
startangle=90,
colors=["#66b3ff", "#ff9999"]
)
plt.title("Emotion Distribution in 'Let It Be'")
plt.show()
"Let It Be" 가사를 분석한 결과, 이 노래는 단순한 반복적인 가사처럼 보이지만 깊은 감정과 희망의 메시지를 담고 있음을 알 수 있었습니다. "Let it be"라는 구절이 무려 36번 등장하며, 이는 평온과 수용의 중요성을 강조하며 듣는 이를 다독이는 위로의 메시지로 작용합니다. 감정 분석 결과, 긍정적인 단어("wisdom", "light", "love")가 부정적인 단어("trouble", "darkness")보다 두 배 이상 많아, 슬픔과 어려움 속에서도 긍정적인 빛을 찾으라는 희망적인 메시지를 전달하고 있습니다. "Wisdom(지혜)"이 반복적으로 등장하며, "지혜롭게 받아들이라"는 조언을 건네는 한편, 반복되는 "let it be"는 삶의 혼란 속에서도 흘러가게 두라는 인생 철학을 상징합니다. 데이터로도 증명된 이 노래의 반복적이고 긍정적인 메시지는 단순한 멜로디 이상의 감정적 안정감을 제공하며, 듣는 이의 마음을 치료하는 감정적 백신과 같습니다.
이제, 여러분도 어려움에 직면했을 때 "Let it be~"를 흥얼거리며 문제를 그냥 흘려보내 보는 건 어떨까요? 😊
import re
from collections import Counter
# 예제 데이터: SNS 게시물
posts = [
"오늘도 좋은 하루! #행복 #일상 #Happy #Life 💕",
"주말 잘 보내세요! #Weekend #행복 #행복 #휴식",
"#Workout 시작! 건강한 하루 #Health #운동 💪",
"일상을 기록하며~ #일상 #기록 #Happy"
]
# 해시태그 추출 함수
def extract_hashtags(posts):
hashtags = []
for post in posts:
# 1. #으로 시작하는 단어 추출
tags = re.findall(r"#\w+", post)
# 2. 특수문자 제거
tags = [re.sub(r"[^가-힣a-zA-Z]", "", tag) for tag in tags]
hashtags.extend(tags)
return hashtags
# 중복 제거 함수
def remove_duplicates(tags):
return list(set(tags))
# 해시태그 빈도수 계산 함수
def calculate_frequencies(tags):
return Counter(tags)
# 해시태그 구분 함수 (한글/알파벳)
def separate_tags_by_language(tags):
korean_tags = [tag for tag in tags if re.search(r"[가-힣]", tag)]
english_tags = [tag for tag in tags if re.search(r"[a-zA-Z]", tag)]
return korean_tags, english_tags
# 실행 과정
# 1. 해시태그 추출
extracted_hashtags = extract_hashtags(posts)
# 2. 중복 제거
unique_hashtags = remove_duplicates(extracted_hashtags)
# 3. 빈도수 계산
hashtag_frequencies = calculate_frequencies(extracted_hashtags)
# 4. 언어별 해시태그 분리
korean_tags, english_tags = separate_tags_by_language(unique_hashtags)
# 결과 출력
print("추출된 해시태그:", extracted_hashtags)
print("중복 제거된 해시태그:", unique_hashtags)
print("해시태그 빈도수:", dict(hashtag_frequencies))
print("한글 해시태그:", korean_tags)
print("영어 해시태그:", english_tags)
추출된 해시태그: ['행복', '일상', 'Happy', 'Life', 'Weekend', '행복', '행복', '휴식', 'Workout', 'Health', '운동', '일상', '기록', 'Happy']
중복 제거된 해시태그: ['Life', '행복', 'Happy', '기록', 'Workout', '휴식', '일상', 'Weekend', '운동', 'Health']
해시태그 빈도수: {'행복': 3, '일상': 2, 'Happy': 2, 'Life': 1, 'Weekend': 1, '휴식': 1, 'Workout': 1, 'Health': 1, '운동': 1, '기록': 1}
한글 해시태그: ['행복', '기록', '휴식', '일상', '운동']
영어 해시태그: ['Life', 'Happy', 'Workout', 'Weekend', 'Health']
- Total
- Today
- Yesterday