03-140. 비정형데이터 분석
비정형 데이터 분석
비정형데이터는 정해진 구조나 형식이 없는 데이터를 말하는데 정형데이터와 반대로 표 형태로 쉽게 정리할 수 없는 데이터를 말한다. 주로 텍스트, 이미지, 오디오, 동영상, 로그파일 등이다.
전체 데이터의 80% 이상이 비정형데이터라고 알려져 있으며, 최근 소셜미디어, IoT 센서, 웹 로그 등의 증가로 비정형데이터의 양이 폭발적으로 늘어나고 있다. 비정형데이터를 분석하여 인사이트를 얻는 것은 현대 데이터 분석의 핵심 과제 중 하나이다.
비정형데이터의 특징
- 구조의 복잡함: 데이터의 구조가 일정하지 않고 미리 정의된 스키마가 없다
- 형태의 다양함: 텍스트, 이미지, 음성, 동영상 등 다양한 형태로 존재한다
- 크기가 가변적: 데이터의 길이, 내용, 형식이 매우 다양하다
- 처리하기 복잡함: 분석 및 처리에 추가적인 전처리(텍스트 마이닝, 이미지 분석 등)가 필요하다
- 가치가 높음: 적절히 분석하면 정형데이터에서 얻을 수 없는 깊은 인사이트를 제공한다
비정형데이터는 자체로는 가치가 높지 않지만 많은 양의 데이터를 가공해서 처리하면 가치가 더 찾아낼 수 있다.
비정형데이터의 유형
텍스트 데이터
- 소셜미디어 게시물: 트위터, 페이스북, 인스타그램 등의 게시글
- 리뷰 및 평점: 제품 리뷰, 서비스 후기, 평가 댓글
- 뉴스 기사: 온라인 뉴스, 블로그 포스트, 기사 댓글
- 이메일 및 메시지: 고객 문의, 내부 커뮤니케이션
- 문서: 보고서, 계약서, 매뉴얼 등
이미지 데이터
- 사진: 제품 이미지, 사용자 업로드 사진
- 의료 영상: X-ray, MRI, CT 스캔 이미지
- 위성 이미지: 지리 정보, 환경 모니터링 데이터
- 보안 영상: CCTV, 감시 카메라 영상
오디오/비디오 데이터
- 음성 녹음: 고객 상담 통화, 회의 녹음
- 동영상: 유튜브 콘텐츠, 광고 영상, 교육 자료
- 팟캐스트: 오디오 콘텐츠, 인터뷰
센서 및 로그 데이터
- IoT 센서 데이터: 온도, 습도, 위치 정보
- 웹 로그: 서버 접속 기록, 사용자 행동 로그
- 시스템 로그: 애플리케이션 오류, 성능 모니터링 데이터
텍스트 데이터 분석
텍스트 데이터는 가장 일반적인 비정형데이터로, 자연어처리(NLP) 기술을 사용하여 분석한다. 텍스트 데이터전커리는 매우 복잡하고 다양하다. 텍스트마이닝(Tex tmining)이나 정보검색(Information Retrieval)에서 사용하는 기술을 많이 쓴다.
간단한 고객 리뷰글에 대한 분석을 위해서 텍스트 데이터 전처리하는 것을 알아보자.
텍스트 전처리
import re
import pandas as pd
from collections import Counter
import matplotlib.pyplot as plt
from wordcloud import WordCloud
import seaborn as sns
# 텍스트 데이터 예시
reviews = [
"이 제품 정말 좋아요! 품질이 뛰어나고 배송도 빨라서 만족합니다.",
"가격 대비 괜찮은 것 같아요. 디자인도 예쁘고 실용적이에요.",
"배송이 너무 늦었어요. 제품은 괜찮지만 서비스가 아쉽습니다.",
"품질이 기대 이하였습니다. 사진과 실제가 많이 달라요.",
"정말 만족스러운 구매였어요! 다음에도 이용하고 싶습니다."
]
def preprocess_text(text):
"""텍스트 전처리 함수"""
# 특수문자 제거 (한글, 영문, 숫자, 공백만 유지)
text = re.sub(r'[^가-힣a-zA-Z0-9\s]', '', text)
# 연속된 공백을 하나로 변경
text = re.sub(r'\s+', ' ', text)
# 앞뒤 공백 제거
text = text.strip()
return text
# 텍스트 전처리 적용
processed_reviews = [preprocess_text(review) for review in reviews]
print("원본 텍스트:")
for i, review in enumerate(reviews[:2]):
print(f"{i+1}: {review}")
print("\n전처리된 텍스트:")
for i, review in enumerate(processed_reviews[:2]):
print(f"{i+1}: {review}")
특수문자와 연속된 공백은 단어 목록을 뽑아서 분석할 때 같은 의미이지만 다르게 추출되는 단어가 생기고 빈 단어가 생기는 문제가 있다. 제거하는 것이 일반적이다.
단어 빈도 분석
# 모든 텍스트를 하나로 합치기
all_text = ' '.join(processed_reviews)
# 단어 분리 및 빈도 계산
words = all_text.split()
word_freq = Counter(words)
print("가장 자주 나오는 단어 Top 10:")
for word, freq in word_freq.most_common(10):
print(f"{word}: {freq}번")
# 단어 빈도를 데이터프레임으로 변환
word_df = pd.DataFrame(word_freq.most_common(10),
columns=['단어', '빈도'])
# 시각화
plt.figure(figsize=(12, 5))
# 단어 빈도 막대그래프
plt.subplot(1, 2, 1)
sns.barplot(data=word_df, x='빈도', y='단어', palette='viridis')
plt.title('단어 빈도 분석')
plt.xlabel('빈도')
# 워드클라우드 (한글 폰트 설정 필요)
plt.subplot(1, 2, 2)
try:
# Windows의 경우 'malgun.ttf', Mac의 경우 'AppleGothic.ttf'
wordcloud = WordCloud(
font_path='malgun.ttf', # 한글 폰트 경로
background_color='white',
width=400, height=300,
max_words=50
).generate(all_text)
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
plt.title('워드클라우드')
except:
plt.text(0.5, 0.5, '한글 폰트 설정 필요',
ha='center', va='center', transform=plt.gca().transAxes)
plt.title('워드클라우드 (폰트 설정 필요)')
plt.tight_layout()
plt.show()
감정 분석
def analyze_sentiment(text):
"""간단한 감정 분석 함수"""
positive_words = ['좋아요', '만족', '뛰어나', '예쁘고', '빨라서', '괜찮', '만족스러운']
negative_words = ['늦었어요', '아쉽습니다', '기대 이하', '달라요']
positive_count = sum(1 for word in positive_words if word in text)
negative_count = sum(1 for word in negative_words if word in text)
if positive_count > negative_count:
return 'positive'
elif negative_count > positive_count:
return 'negative'
else:
return 'neutral'
# 각 리뷰의 감정 분석
sentiment_results = []
for i, review in enumerate(reviews):
sentiment = analyze_sentiment(review)
sentiment_results.append({
'review_id': i+1,
'text': review,
'sentiment': sentiment,
'length': len(review)
})
# 결과를 데이터프레임으로 변환
sentiment_df = pd.DataFrame(sentiment_results)
print("감정 분석 결과:")
print(sentiment_df)
# 감정 분포 시각화
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
sentiment_counts = sentiment_df['sentiment'].value_counts()
plt.pie(sentiment_counts.values, labels=sentiment_counts.index, autopct='%1.1f%%')
plt.title('감정 분포')
plt.subplot(1, 2, 2)
sns.boxplot(data=sentiment_df, x='sentiment', y='length')
plt.title('감정별 리뷰 길이 분포')
plt.xlabel('감정')
plt.ylabel('텍스트 길이')
plt.tight_layout()
plt.show()
고급 텍스트 분석
# TF-IDF를 사용한 키워드 추출
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
import numpy as np
# TF-IDF 벡터화
vectorizer = TfidfVectorizer(max_features=100, stop_words=None)
tfidf_matrix = vectorizer.fit_transform(processed_reviews)
# 특성 이름 (단어들)
feature_names = vectorizer.get_feature_names_out()
# 각 문서별 중요한 단어 추출
def get_top_keywords(doc_index, top_k=3):
"""문서별 상위 키워드 추출"""
doc_tfidf = tfidf_matrix[doc_index].toarray()[0]
top_indices = doc_tfidf.argsort()[-top_k:][::-1]
keywords = []
for idx in top_indices:
if doc_tfidf[idx] > 0:
keywords.append((feature_names[idx], doc_tfidf[idx]))
return keywords
print("문서별 주요 키워드:")
for i in range(len(reviews)):
keywords = get_top_keywords(i)
print(f"리뷰 {i+1}: {[word for word, score in keywords]}")
# 텍스트 클러스터링
kmeans = KMeans(n_clusters=2, random_state=42)
clusters = kmeans.fit_predict(tfidf_matrix)
# 클러스터 결과 추가
sentiment_df['cluster'] = clusters
print("\n클러스터링 결과:")
for cluster_id in range(2):
cluster_reviews = sentiment_df[sentiment_df['cluster'] == cluster_id]
print(f"\n클러스터 {cluster_id}:")
for _, row in cluster_reviews.iterrows():
print(f" - {row['text'][:50]}...")
이미지 데이터 분석
이미지 데이터는 컴퓨터 비전 기술을 사용하여 분석한다.
이미지 기본 분석
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import cv2
def analyze_image_basic(image_path):
"""이미지 기본 정보 분석"""
try:
# PIL로 이미지 로드
img_pil = Image.open(image_path)
print(f"이미지 크기: {img_pil.size}")
print(f"이미지 모드: {img_pil.mode}")
print(f"이미지 포맷: {img_pil.format}")
# numpy 배열로 변환
img_array = np.array(img_pil)
print(f"배열 형태: {img_array.shape}")
print(f"픽셀 값 범위: {img_array.min()} ~ {img_array.max()}")
return img_array
except Exception as e:
print(f"이미지 로드 오류: {e}")
# 샘플 이미지 생성 (실제 이미지가 없을 때)
return np.random.randint(0, 255, (300, 400, 3), dtype=np.uint8)
def visualize_image_analysis(img_array):
"""이미지 분석 시각화"""
plt.figure(figsize=(15, 5))
# 원본 이미지
plt.subplot(1, 4, 1)
plt.imshow(img_array)
plt.title('원본 이미지')
plt.axis('off')
# RGB 히스토그램
plt.subplot(1, 4, 2)
colors = ['red', 'green', 'blue']
for i, color in enumerate(colors):
if len(img_array.shape) == 3: # 컬러 이미지
plt.hist(img_array[:,:,i].flatten(), bins=50, alpha=0.7,
color=color, label=f'{color.upper()}')
else: # 그레이스케일
plt.hist(img_array.flatten(), bins=50, alpha=0.7,
color='gray', label='Gray')
break
plt.title('색상 히스토그램')
plt.xlabel('픽셀 값')
plt.ylabel('빈도')
plt.legend()
# 그레이스케일 변환
plt.subplot(1, 4, 3)
if len(img_array.shape) == 3:
gray_img = np.mean(img_array, axis=2)
else:
gray_img = img_array
plt.imshow(gray_img, cmap='gray')
plt.title('그레이스케일')
plt.axis('off')
# 엣지 검출
plt.subplot(1, 4, 4)
gray_uint8 = gray_img.astype(np.uint8)
edges = cv2.Canny(gray_uint8, 100, 200)
plt.imshow(edges, cmap='gray')
plt.title('엣지 검출')
plt.axis('off')
plt.tight_layout()
plt.show()
# 샘플 이미지로 분석 실행
sample_img = analyze_image_basic('sample_image.jpg') # 실제 파일이 없으면 랜덤 이미지 생성
visualize_image_analysis(sample_img)
이미지 특성 추출
def extract_image_features(img_array):
"""이미지에서 기본 특성 추출"""
features = {}
# 그레이스케일 변환
if len(img_array.shape) == 3:
gray = np.mean(img_array, axis=2)
else:
gray = img_array
# 기본 통계 특성
features['평균_밝기'] = np.mean(gray)
features['밝기_표준편차'] = np.std(gray)
features['최대_밝기'] = np.max(gray)
features['최소_밝기'] = np.min(gray)
# 색상 특성 (컬러 이미지인 경우)
if len(img_array.shape) == 3:
features['평균_R'] = np.mean(img_array[:,:,0])
features['평균_G'] = np.mean(img_array[:,:,1])
features['평균_B'] = np.mean(img_array[:,:,2])
# 텍스처 특성 (간단한 버전)
# 그래디언트 계산
grad_x = np.abs(np.diff(gray, axis=1))
grad_y = np.abs(np.diff(gray, axis=0))
features['텍스처_복잡도'] = np.mean(grad_x) + np.mean(grad_y)
return features
# 여러 이미지의 특성 비교 (샘플 데이터)
image_features = []
for i in range(5):
# 다양한 특성을 가진 샘플 이미지 생성
if i % 2 == 0:
# 밝은 이미지
sample_img = np.random.randint(150, 255, (200, 300, 3), dtype=np.uint8)
else:
# 어두운 이미지
sample_img = np.random.randint(0, 100, (200, 300, 3), dtype=np.uint8)
features = extract_image_features(sample_img)
features['이미지_ID'] = f'이미지_{i+1}'
image_features.append(features)
# 특성을 데이터프레임으로 변환
features_df = pd.DataFrame(image_features)
print("이미지 특성 분석 결과:")
print(features_df)
# 특성 시각화
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.scatter(features_df['평균_밝기'], features_df['텍스처_복잡도'])
plt.xlabel('평균 밝기')
plt.ylabel('텍스처 복잡도')
plt.title('밝기 vs 텍스처 복잡도')
plt.subplot(1, 3, 2)
features_df[['평균_R', '평균_G', '평균_B']].plot(kind='bar', ax=plt.gca())
plt.title('이미지별 평균 RGB 값')
plt.xticks(rotation=45)
plt.subplot(1, 3, 3)
plt.hist(features_df['평균_밝기'], bins=10, alpha=0.7)
plt.xlabel('평균 밝기')
plt.ylabel('빈도')
plt.title('밝기 분포')
plt.tight_layout()
plt.show()
비정형데이터 분석의 도전과제와 해결방안
데이터 품질 문제
- 노이즈가 많은 데이터
- 불완전하거나 일관성 없는 데이터
- 편향된 데이터
처리 복잡성
- 높은 계산 비용
- 복잡한 전처리 과정
- 실시간 처리의 어려움
해석의 어려움
- 주관적 해석 가능성
- 컨텍스트 의존성
- 문화적/언어적 차이
해결방안
class DataQualityChecker:
"""데이터 품질 검사 도구"""
def __init__(self):
self.quality_metrics = {}
def check_text_quality(self, texts):
"""텍스트 데이터 품질 검사"""
quality_issues = []
for i, text in enumerate(texts):
issues = []
# 길이 검사
if len(text.strip()) < 10:
issues.append('too_short')
# 특수문자 비율 검사
special_char_ratio = len(re.findall(r'[^\w\s]', text)) / len(text)
if special_char_ratio > 0.3:
issues.append('too_many_special_chars')
# 반복 패턴 검사
if len(set(text.split())) / len(text.split()) < 0.5:
issues.append('repetitive_content')
if issues:
quality_issues.append({
'index': i,
'text': text[:50] + '...',
'issues': issues
})
return quality_issues
def suggest_improvements(self, quality_issues):
"""품질 개선 제안"""
suggestions = []
for issue in quality_issues:
for problem in issue['issues']:
if problem == 'too_short':
suggestions.append(f"텍스트 {issue['index']}: 더 상세한 내용 필요")
elif problem == 'too_many_special_chars':
suggestions.append(f"텍스트 {issue['index']}: 특수문자 정제 필요")
elif problem == 'repetitive_content':
suggestions.append(f"텍스트 {issue['index']}: 중복 내용 제거 필요")
return suggestions
# 사용 예시
quality_checker = DataQualityChecker()
sample_texts = [
"좋아요", # 너무 짧음
"!@#$%^&*()!@#$%^&*()", # 특수문자 과다
"좋아요 좋아요 좋아요 좋아요 좋아요", # 반복적
"이 제품은 정말 훌륭합니다. 품질도 좋고 가격도 합리적이에요." # 정상
]
issues = quality_checker.check_text_quality(sample_texts)
suggestions = quality_checker.suggest_improvements(issues)
print("=== 데이터 품질 검사 결과 ===")
for suggestion in suggestions:
print(f"💡 {suggestion}")
마무리
핵심 포인트
- 비정형데이터의 중요성: 전체 데이터의 80% 이상을 차지하며 귀중한 인사이트 제공
- 다양한 분석 기법: 텍스트 마이닝, 이미지 분석, 로그 분석 등 각 데이터 유형별 특화 기법
- 생성형 AI의 활용: LLM을 통한 효율적인 비정형데이터 처리 및 분석
- 실무 적용: 고객 피드백 분석, 실시간 모니터링 등 다양한 비즈니스 활용 사례
향후 전망
- AI 기술 발전: 더욱 정교한 자연어처리 및 컴퓨터 비전 기술
- 실시간 처리: 스트리밍 데이터 처리 기술의 발전
- 멀티모달 분석: 텍스트, 이미지, 음성을 통합한 분석 기법
- 자동화: 전처리부터 인사이트 도출까지 자동화된 파이프라인
비정형데이터 분석은 현대 데이터 과학의 핵심 영역으로, 적절한 도구와 기법을 활용하면 정형데이터에서는 얻을 수 없는 깊이 있는 인사이트를 제공할 수 있다. 특히 생성형 AI의 발전으로 비정형데이터 분석이 더욱 접근하기 쉬워지고 있어, 앞으로 더 많은 분야에서 활용될 것으로 예상된다.