콘텐츠로 이동
Data Prep
상세

Fake News Detection

텍스트 분류를 활용한 가짜 뉴스 탐지 프로젝트.

프로젝트 개요

항목 내용
목표 뉴스 기사의 진위 여부 자동 분류
데이터 fake_or_real_news.csv (~30MB)
기법 텍스트 분류 (NLP)
언어 Python
상태 초기 탐색

데이터셋

파일 정보

항목 내용
파일명 fake_or_real_news.csv
크기 ~30MB
위치 iCloud/03_Projects/Python/

예상 구조

| id | title | text | label |
|----|-------|------|-------|
| 1  | ...   | ...  | REAL  |
| 2  | ...   | ...  | FAKE  |

분석 접근법

1. 탐색적 데이터 분석 (EDA)

import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv('fake_or_real_news.csv')

# 기본 정보
print(df.info())
print(df['label'].value_counts())

# 텍스트 길이 분포
df['text_length'] = df['text'].str.len()
df.groupby('label')['text_length'].describe()

2. 전처리 파이프라인

import re
from sklearn.feature_extraction.text import TfidfVectorizer

def preprocess_text(text):
    """텍스트 전처리"""
    # 소문자 변환
    text = text.lower()

    # 특수문자 제거
    text = re.sub(r'[^a-zA-Z\s]', '', text)

    # 불용어 제거 (선택적)
    # text = remove_stopwords(text)

    return text

# TF-IDF 벡터화
vectorizer = TfidfVectorizer(
    max_features=10000,
    ngram_range=(1, 2),
    stop_words='english'
)

X = vectorizer.fit_transform(df['text'].apply(preprocess_text))
y = df['label'].map({'REAL': 0, 'FAKE': 1})

3. 모델링 접근법

전통 ML

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import MultinomialNB
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

models = {
    'Logistic Regression': LogisticRegression(max_iter=1000),
    'Naive Bayes': MultinomialNB(),
    'Random Forest': RandomForestClassifier(n_estimators=100)
}

for name, model in models.items():
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    print(f"\n{name}:")
    print(classification_report(y_test, y_pred))

딥러닝 (BERT)

from transformers import BertTokenizer, BertForSequenceClassification
from transformers import Trainer, TrainingArguments
import torch

# 토크나이저
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

# 데이터셋 준비
class NewsDataset(torch.utils.data.Dataset):
    def __init__(self, texts, labels, tokenizer, max_length=512):
        self.texts = texts
        self.labels = labels
        self.tokenizer = tokenizer
        self.max_length = max_length

    def __len__(self):
        return len(self.texts)

    def __getitem__(self, idx):
        encoding = self.tokenizer(
            self.texts[idx],
            truncation=True,
            padding='max_length',
            max_length=self.max_length,
            return_tensors='pt'
        )
        return {
            'input_ids': encoding['input_ids'].squeeze(),
            'attention_mask': encoding['attention_mask'].squeeze(),
            'labels': torch.tensor(self.labels[idx])
        }

# 모델
model = BertForSequenceClassification.from_pretrained(
    'bert-base-uncased', num_labels=2
)

# 학습
training_args = TrainingArguments(
    output_dir='./results',
    num_train_epochs=3,
    per_device_train_batch_size=16,
    evaluation_strategy='epoch'
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset
)

trainer.train()

평가 지표

지표 설명 중요도
Accuracy 전체 정확도 기본
Precision (FAKE) 가짜 뉴스 탐지 정밀도 높음
Recall (FAKE) 가짜 뉴스 탐지율 높음
F1-Score 정밀도/재현율 조화평균 핵심
AUC-ROC 분류 임계값 무관 성능 참고

오분류 비용

오류 유형 결과 비용
FP (REAL→FAKE) 진짜 뉴스를 가짜로 중간
FN (FAKE→REAL) 가짜 뉴스를 진짜로 높음

→ Recall 중시 (가짜 뉴스 놓치지 않기)

피처 분석

중요 피처 예시

# TF-IDF 상위 피처
feature_names = vectorizer.get_feature_names_out()
coefficients = model.coef_[0]

# FAKE 관련 상위 단어
fake_indicators = sorted(
    zip(feature_names, coefficients),
    key=lambda x: x[1],
    reverse=True
)[:20]

# REAL 관련 상위 단어
real_indicators = sorted(
    zip(feature_names, coefficients),
    key=lambda x: x[1]
)[:20]

예상 패턴

구분 특징
FAKE 감정적 어조, 과장 표현, 출처 불분명
REAL 객관적 어조, 인용 포함, 구체적 수치

확장 가능성

1. 멀티모달 분석

  • 이미지 검증 (역이미지 검색)
  • 소셜 미디어 확산 패턴

2. 실시간 탐지

# API 엔드포인트 예시
from fastapi import FastAPI

app = FastAPI()

@app.post("/detect")
async def detect_fake_news(text: str):
    # 전처리
    processed = preprocess_text(text)

    # 벡터화
    vector = vectorizer.transform([processed])

    # 예측
    prediction = model.predict(vector)[0]
    probability = model.predict_proba(vector)[0]

    return {
        "prediction": "FAKE" if prediction == 1 else "REAL",
        "confidence": float(max(probability)),
        "probabilities": {
            "REAL": float(probability[0]),
            "FAKE": float(probability[1])
        }
    }

3. 설명 가능성

import lime
from lime.lime_text import LimeTextExplainer

explainer = LimeTextExplainer(class_names=['REAL', 'FAKE'])

def predict_proba(texts):
    vectors = vectorizer.transform(texts)
    return model.predict_proba(vectors)

# 특정 기사 설명
explanation = explainer.explain_instance(
    article_text,
    predict_proba,
    num_features=10
)
explanation.show_in_notebook()

참고 자료

데이터셋

논문

논문 연도 기여
Detecting Fake News on Social Media 2017 초기 ML 접근
BERT for Fake News Detection 2019 Transformer 적용
Multimodal Fake News Detection 2021 이미지+텍스트

파일 위치

  • 데이터: ~/Library/Mobile Documents/com~apple~CloudDocs/03_Projects/Python/fake_or_real_news.csv
  • 코드: ~/Library/Mobile Documents/com~apple~CloudDocs/03_Projects/Python/fakenews.py