# 신문과방송 기사 성능 예측 모델의 학습 및 추론 과정 이 문서는 `train_and_save_models.py` 스크립트가 어떻게 기사 데이터를 기반으로 조회수 예측 및 주요 청중 연령대 예측 모델을 학습시키고, 학습된 모델을 사용하여 추론하는지에 대한 자세한 설명입니다. 모든 과정은 한국어로 설명하며, 코드의 주요 구성 요소와 단계별 흐름을 다룹니다. ## 1. 개요 이 코드는 "신문과방송" 프로젝트의 일환으로, 기사의 제목과 내용, 카테고리 등의 정보를 활용하여 두 가지 주요 예측을 수행합니다: - **조회수 예측**: 기사의 예상 조회수를 예측하는 회귀 모델. - **주요 청중 연령대 예측**: 기사를 가장 많이 읽는 연령대를 예측하는 분류 모델. 모델은 XGBoost (Extreme Gradient Boosting)를 기반으로 하며, 텍스트 데이터를 TF-IDF (Term Frequency-Inverse Document Frequency)로 변환하고, 카테고리 데이터를 원-핫 인코딩하여 특징으로 사용합니다. 학습 과정에서는 Optuna를 사용하여 하이퍼파라미터 튜닝을 수행하며, 과적합을 방지하기 위해 조기 종료(Early Stopping)를 적용합니다. 추론 시에는 학습된 모델과 특징 변환기를 사용하여 새로운 기사 데이터를 입력으로 받아 예측을 수행합니다. 또한, 유사 기사 탐색 기능도 포함되어 있습니다. ## 2. 데이터 준비 학습을 시작하기 전에 필요한 데이터를 로드하고 전처리합니다. ### 2.1 데이터 로딩 - **파일 경로**: `./data_csv/` 디렉토리에서 다음 CSV 파일을 로드합니다. - `contents.csv`: 기사의 제목, 내용, 카테고리, 기사 ID 등의 기본 정보. - `article_metrics_monthly.csv`: 기사별 월별 조회수, 댓글 수, 좋아요 수 등의 메트릭 데이터. - `demographics_merged.csv`: 기사별 연령대별 조회수 데이터. - **확인**: 파일이 존재하지 않으면 오류를 발생시키고 실행을 중단합니다. ### 2.2 데이터 전처리 - **메트릭 집계**: `article_metrics_monthly.csv`의 데이터를 기사 ID별로 그룹화하여 총 조회수(`views_total`), 총 댓글 수(`comments_total`), 총 좋아요 수(`likes_total`)를 계산합니다. - **주요 청중 식별**: `demographics_merged.csv`에서 "전체" 연령대를 제외하고, 각 기사별로 조회수가 가장 높은 연령대를 `primary_age_group`으로 선정합니다. 이는 분류 모델의 타겟이 됩니다. - **데이터 병합**: `contents.csv`를 기준으로 메트릭 데이터와 주요 청중 데이터를 왼쪽 조인(Left Join)하여 마스터 데이터프레임을 생성합니다. 누락된 값은 0으로 채웁니다. 이 단계에서 생성된 `df_master` 데이터프레임은 기사별로 제목, 내용, 카테고리, 총 조회수, 총 댓글 수, 총 좋아요 수, 주요 연령대를 포함합니다. ## 3. 특징 공학 (Feature Engineering) 기사 데이터를 머신러닝 모델이 이해할 수 있는 숫자 특징으로 변환합니다. ### 3.1 텍스트 특징 추출 - **토크나이저**: Konlpy의 Okt를 사용하여 텍스트를 형태소 분석합니다. 명사(Noun)와 동사(Verb)만 추출하며, 어간 추출(Stemming)을 적용합니다. - **TF-IDF 변환**: 제목과 내용을 결합한 텍스트를 TfidfVectorizer로 변환합니다. - 최대 특징 수: 5000개. - 토크나이저: Okt 기반 사용자 정의 함수. - 결과: 희소 행렬 `X_text` (텍스트 특징). - **병렬 처리**: 원래 코드에 병렬 토크나이저 클래스가 정의되어 있지만, 실제로는 단일 프로세스 토크나이저를 사용합니다. 대용량 데이터의 경우 병렬화를 고려할 수 있습니다. ### 3.2 카테고리 특징 추출 - **원-핫 인코딩**: `category` 열을 OneHotEncoder로 변환합니다. - 알 수 없는 카테고리는 무시합니다. - 결과: 희소 행렬 `X_cat` (카테고리 특징). ### 3.3 특징 결합 - 텍스트 특징과 카테고리 특징을 수평으로 결합하여 `X_combined` 행렬을 생성합니다. 이는 최종 입력 특징 행렬입니다. ## 4. 타겟 준비 (Target Preparation) 예측할 타겟 변수를 준비하고, 유효한 샘플만 필터링합니다. ### 4.1 조회수 타겟 (Regression Target) - **로그 변환**: 조회수(`views_total`)의 분포가 치우쳐져 있으므로, `np.log1p`를 적용하여 로그 변환합니다. 이는 모델의 예측 성능을 향상시키며, 나중에 `np.expm1`로 원래 스케일로 복원합니다. - 0인 값은 `log1p`로 안전하게 처리됩니다. ### 4.2 연령대 타겟 (Classification Target) - `primary_age_group`을 문자열로 변환하고, LabelEncoder로 정수 레이블로 인코딩합니다. - 유효한 샘플 필터링: 연령대가 누락된 샘플을 제외합니다. ### 4.3 최종 필터링 - 유효한 샘플에 대해서만 `X_combined`, `X_text`, 조회수 타겟, 연령대 타겟을 유지합니다. - 기사 매핑: 유효한 기사 ID와 제목을 저장하여 나중에 유사 기사 탐색에 사용합니다. ## 5. 모델 학습 (Model Training) XGBoost 모델을 학습시키고, Optuna로 하이퍼파라미터를 튜닝합니다. ### 5.1 데이터 분할 - 데이터를 훈련 세트와 검증 세트로 분할합니다 (기본: 80% 훈련, 20% 검증). - 층화 샘플링(Stratified Sampling)을 적용하여 연령대 분포를 유지합니다. ### 5.2 하이퍼파라미터 튜닝 - **Optuna 사용**: 자동화된 하이퍼파라미터 최적화를 수행합니다. - 회귀 모델(XGBRegressor): n_estimators, learning_rate, max_depth, subsample, colsample_bytree 등을 튜닝. 목표: RMSE 최소화. - 분류 모델(XGBClassifier): 유사한 파라미터를 튜닝. 목표: 로그 손실 최소화. - **프루닝**: Optuna의 MedianPruner와 XGBoostPruningCallback을 사용하여 비효율적인 시도를 조기 종료합니다. - 튜닝 횟수: 각 모델당 50회 (시간 제한: 600초). ### 5.3 최종 모델 학습 - 최적 하이퍼파라미터로 전체 데이터셋에 대해 모델을 학습합니다. - **회귀 모델**: 조회수 예측. 조기 종료를 적용하여 과적합 방지. - **분류 모델**: 연령대 예측. 다중 클래스 소프트맥스 손실 사용. - **평가**: 검증 세트에서 MAE (Mean Absolute Error)와 정확도(Accuracy)를 계산하여 성능을 로그에 기록합니다. ### 5.4 아티팩트 저장 - 학습된 모델, 벡터라이저, 인코더 등을 Pickle 파일로 저장합니다. - tfidf_vectorizer.pkl: TF-IDF 벡터라이저. - onehot_encoder.pkl: 원-핫 인코더. - label_encoder.pkl: 레이블 인코더. - view_prediction_model.pkl: 조회수 예측 모델. - age_prediction_model.pkl: 연령대 예측 모델. - text_features_matrix.pkl: 텍스트 특징 행렬 (유사 기사 탐색용). - article_mapping.pkl: 기사 ID와 제목 매핑. ## 6. 추론 과정 (Inference Process) 학습된 모델을 사용하여 새로운 기사에 대해 예측을 수행합니다. (이 코드는 학습 파이프라인만 포함하므로, 추론은 별도 스크립트에서 수행해야 합니다.) ### 6.1 입력 준비 - 새로운 기사의 제목, 내용, 카테고리를 입력받습니다. - 텍스트: TF-IDF 벡터라이저로 변환. - 카테고리: 원-핫 인코더로 변환. - 특징 결합: 텍스트와 카테고리 특징을 결합. ### 6.2 예측 수행 - **조회수 예측**: 회귀 모델로 로그 변환된 값을 예측한 후, `np.expm1`로 원래 조회수로 복원. - **연령대 예측**: 분류 모델로 확률을 예측하고, 레이블 인코더로 원래 연령대로 디코딩. ### 6.3 출력 - 예측된 조회수와 주요 연령대를 반환합니다. ## 7. 추가 기능: 유사 기사 탐색 (Similar Article Search) 코드의 마지막 부분에서 유사 기사를 찾는 기능을 시연합니다. - **방법**: 코사인 유사도(Cosine Similarity)를 사용하여 텍스트 특징 기반으로 유사한 기사를 찾습니다. - **입력**: 기사 ID. - **출력**: 상위 N개 유사 기사 (기본: 5개), 유사도 점수 포함. - **용도**: 콘텐츠 기반 추천이나 분석에 활용. ## 8. 실행 및 주의사항 - **실행**: `python train_and_save_models.py`로 스크립트를 실행합니다. - **종속성**: Optuna, XGBoost, Konlpy, Scikit-learn 등이 필요합니다. `requirements.txt`를 참고하세요. - **성능**: 대용량 데이터의 경우 병렬 토크나이징을 고려하세요. - **개선점**: 로그 변환, 튜닝, 조기 종료 등이 모델 정확도를 향상시킵니다. 이 설명은 코드의 모든 주요 단계를 커버합니다. 추가 질문이 있으면 언제든지 물어보세요!