Spaces:
Sleeping
Sleeping
| # -*- coding: utf-8 -*- | |
| """ | |
| ์ ๋ฌธ๊ณผ๋ฐฉ์ก ๋ ์ ๋ฐ์ดํฐ ์ฌ์ธต ํ์์ ๋ฐ์ดํฐ ๋ถ์ (Advanced EDA) | |
| ์ด ์คํฌ๋ฆฝํธ๋ ๋ค์ 4๊ฐ์ ๋ฐ์ดํฐ์ ์ ํ์ฉํ์ฌ ์ ๋ฌธ๊ณผ๋ฐฉ์ก ๋ ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ธต ๋ถ์ํฉ๋๋ค. | |
| 1. article_metrics_monthly.csv: ๊ธฐ์ฌ๋ณ ์๊ฐ ์งํ (์กฐํ์, ์ข์์, ๋๊ธ) | |
| 2. contents.csv: ๊ธฐ์ฌ ์ฝํ ์ธ ์ ๋ณด (์นดํ ๊ณ ๋ฆฌ, ์ ๋ชฉ, ํ๊ทธ ๋ฑ) | |
| 3. demographics_merged.csv: ๊ธฐ์ฌ๋ณ ์ธ๊ตฌํต๊ณํ์ ๋ ์ ๋ฐ์ดํฐ | |
| 4. referrer.csv: ๊ธฐ์ฌ๋ณ ์ ์ ๊ฒฝ๋ก ๋ฐ์ดํฐ | |
| ์ฃผ์ ๋ถ์ ๋ด์ฉ: | |
| - ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ ๋ฐ ํผ์ฒ ์์ง๋์ด๋ง | |
| - ๊ธฐ์ฌ ํต์ฌ ์งํ(์กฐํ์, ์ข์์, ๋๊ธ) ๋ถํฌ ๋ฐ ์๊ด๊ด๊ณ ๋ถ์ | |
| - ์ฝํ ์ธ ์นดํ ๊ณ ๋ฆฌ๋ณ ์ฑ๊ณผ ๋ฐ ๋ ์ ์ฐธ์ฌ๋ ์ฌ์ธต ๋ถ์ | |
| - ํ๊ทธ ๋ถ์ (Word Cloud ํฌํจ) | |
| - ์ธ๊ตฌํต๊ณ(์ฐ๋ น/์ฑ๋ณ) ๊ทธ๋ฃน๋ณ ์ ํธ ์นดํ ๊ณ ๋ฆฌ ๋ถ์ (ํํธ๋งต) | |
| - ์ ์ ๊ฒฝ๋ก๋ณ ์ฑ๊ณผ ๋ฐ ํจ์จ์ฑ ๋ถ์ | |
| - ์ข ํฉ ์ธ์ฌ์ดํธ ๋์ถ ๋ฐ ๋ฆฌํฌํธ ์๋ ์์ฑ | |
| ์คํ ๋ฐฉ๋ฒ: | |
| - ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๊ธฐ ์ , DATA_DIR ๊ฒฝ๋ก๋ฅผ ์ค์ ๋ฐ์ดํฐ๊ฐ ์๋ ํด๋๋ก ์์ ํ์ธ์. | |
| - ์คํ ์ ์คํฌ๋ฆฝํธ์ ๋์ผํ ์์น์ 'output' ํด๋๊ฐ ์์ฑ๋๋ฉฐ, ๋ชจ๋ ์๊ฐํ ์๋ฃ์ ์ต์ข ์ธ์ฌ์ดํธ ๋ณด๊ณ ์๊ฐ ์ ์ฅ๋ฉ๋๋ค. | |
| """ | |
| # 1. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ํฌํธ | |
| import pandas as pd | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| import seaborn as sns | |
| from datetime import datetime | |
| import warnings | |
| import os | |
| from wordcloud import WordCloud | |
| warnings.filterwarnings('ignore') | |
| # 2. ๊ธฐ๋ณธ ์ค์ ๋ฐ ์ ์ญ ๋ณ์ | |
| def setup_environment(): | |
| """๋ถ์ ํ๊ฒฝ ์ค์ (๊ฒฝ๋ก, ์๊ฐํ ์คํ์ผ)""" | |
| # === ๊ฒฝ๋ก ์ค์ (์ฌ์ฉ์ ํ๊ฒฝ์ ๋ง๊ฒ ์์ ) === | |
| DATA_DIR = r'Broadcast_paper\data_csv' | |
| OUTPUT_DIR = r'./output_analysis' | |
| # ์ถ๋ ฅ ํด๋ ์์ฑ | |
| if not os.path.exists(OUTPUT_DIR): | |
| os.makedirs(OUTPUT_DIR) | |
| print(f"'{OUTPUT_DIR}' ํด๋๋ฅผ ์์ฑํ์ต๋๋ค.") | |
| # === ์๊ฐํ ์ค์ === | |
| plt.rc('font', family='Malgun Gothic') | |
| plt.rcParams['axes.unicode_minus'] = False | |
| sns.set(font='Malgun Gothic', rc={'axes.unicode_minus': False}, style='whitegrid') | |
| print("๋ถ์ ํ๊ฒฝ ์ค์ ์๋ฃ!") | |
| return DATA_DIR, OUTPUT_DIR | |
| # 3. ๋ฐ์ดํฐ ๋ก๋ ๋ฐ ์ ์ฒ๋ฆฌ | |
| def load_and_preprocess_data(data_dir): | |
| """๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ๊ณ ๊ธฐ๋ณธ ์ ์ฒ๋ฆฌ๋ฅผ ์ํํฉ๋๋ค.""" | |
| print("\n[๋จ๊ณ 1] ๋ฐ์ดํฐ ๋ก๋ ๋ฐ ์ ์ฒ๋ฆฌ ์์...") | |
| # ๋ฐ์ดํฐ ๋ก๋ | |
| df_metrics = pd.read_csv(f'{data_dir}/article_metrics_monthly.csv') | |
| df_contents = pd.read_csv(f'{data_dir}/contents.csv') | |
| df_demo = pd.read_csv(f'{data_dir}/demographics_merged.csv') | |
| df_referrer = pd.read_csv(f'{data_dir}/referrer.csv') | |
| # --- ์ ์ฒ๋ฆฌ --- | |
| # 1. df_metrics | |
| df_metrics['period'] = pd.to_datetime(df_metrics['period']) | |
| df_metrics['comments'].fillna(0, inplace=True) # ๋๊ธ ๊ฒฐ์ธก์น๋ 0์ผ๋ก ์ฒ๋ฆฌ | |
| # 2. df_contents | |
| df_contents.dropna(subset=['category', 'content', 'date'], inplace=True) # ์ฃผ์ ์ ๋ณด ๊ฒฐ์ธก ํ ์ ๊ฑฐ | |
| df_contents['date'] = pd.to_datetime(df_contents['date']) | |
| df_contents['publish_month'] = df_contents['date'].dt.to_period('M') | |
| df_contents['publish_dayofweek'] = df_contents['date'].dt.day_name() | |
| df_contents['content_length'] = df_contents['content'].str.len() | |
| # 3. df_demo | |
| df_demo_filtered = df_demo[df_demo['age_group'] != '์ ์ฒด'].copy() | |
| # 4. ๋ฐ์ดํฐ ํตํฉ | |
| # ์๋ณ ์งํ๋ฅผ ๊ธฐ์ฌ๋ณ ์ด๊ณ๋ก ์ง๊ณ | |
| article_total_metrics = df_metrics.groupby('article_id').agg({ | |
| 'views_total': 'sum', | |
| 'likes': 'sum', | |
| 'comments': 'sum' | |
| }).reset_index() | |
| # ์ฝํ ์ธ ์ ๋ณด์ ๊ธฐ์ฌ๋ณ ์ด๊ณ ์งํ ๋ณํฉ | |
| df_merged = pd.merge(df_contents, article_total_metrics, on='article_id', how='left') | |
| df_merged.fillna({'views_total': 0, 'likes': 0, 'comments': 0}, inplace=True) | |
| # ์ฐธ์ฌ๋(Engagement Rate) ๊ณ์ฐ: (์ข์์ + ๋๊ธ) / ์กฐํ์ | |
| # ์กฐํ์๊ฐ 0์ธ ๊ฒฝ์ฐ ์ค๋ฅ ๋ฐฉ์ง | |
| df_merged['engagement_rate'] = ( | |
| (df_merged['likes'] + df_merged['comments']) / df_merged['views_total'].replace(0, np.nan) | |
| ) * 100 | |
| print("๋ฐ์ดํฐ ๋ก๋ ๋ฐ ์ ์ฒ๋ฆฌ ์๋ฃ!") | |
| return { | |
| "metrics": df_metrics, | |
| "contents": df_contents, | |
| "demo": df_demo_filtered, | |
| "referrer": df_referrer, | |
| "merged": df_merged | |
| } | |
| # 4. ์์ธ ๋ถ์ ๋ฐ ์๊ฐํ ํจ์๋ค | |
| def analyze_metrics_overview(df_merged, output_dir): | |
| """๊ธฐ์ฌ ์งํ์ ์ ๋ฐ์ ์ธ ๋ถํฌ์ ์๊ด๊ด๊ณ๋ฅผ ๋ถ์ํ๊ณ ์๊ฐํํฉ๋๋ค.""" | |
| print("\n[๋จ๊ณ 2] ๊ธฐ์ฌ ์งํ ์ ๋ฐ ๋ถ์...") | |
| fig, axes = plt.subplots(1, 2, figsize=(18, 7)) | |
| # ์กฐํ์, ์ข์์, ๋๊ธ ๋ถํฌ | |
| sns.histplot(data=df_merged, x='views_total', bins=50, ax=axes[0], kde=True) | |
| axes[0].set_title('๊ธฐ์ฌ๋ณ ์ด ์กฐํ์ ๋ถํฌ', fontsize=16) | |
| axes[0].set_xlabel('์ด ์กฐํ์') | |
| axes[0].set_ylabel('๊ธฐ์ฌ ์') | |
| axes[0].set_xlim(0, df_merged['views_total'].quantile(0.95)) # ์์ 5% ์ด์์ ์ ์ธํ์ฌ ๋ถํฌ ํ์ธ | |
| # ์๊ด๊ด๊ณ ํํธ๋งต | |
| corr = df_merged[['views_total', 'likes', 'comments', 'content_length']].corr() | |
| sns.heatmap(corr, annot=True, cmap='coolwarm', fmt='.2f', ax=axes[1]) | |
| axes[1].set_title('์ฃผ์ ์งํ ๊ฐ ์๊ด๊ด๊ณ', fontsize=16) | |
| plt.tight_layout() | |
| plt.savefig(f'{output_dir}/metrics_overview.png') | |
| plt.close() | |
| print(" - ๊ธฐ์ฌ ์งํ ๋ถํฌ ๋ฐ ์๊ด๊ด๊ณ ๋ถ์ ์๋ฃ. (metrics_overview.png ์ ์ฅ)") | |
| def analyze_content_features(df_merged, output_dir): | |
| """์ฝํ ์ธ ํน์ง(์นดํ ๊ณ ๋ฆฌ, ํ๊ทธ, ๊ธ์ ์, ๋ฐํ ์์ผ)์ ๋ฐ๋ฅธ ์ฑ๊ณผ ๋ถ์""" | |
| print("\n[๋จ๊ณ 3] ์ฝํ ์ธ ํน์ง๋ณ ์ฑ๊ณผ ๋ถ์...") | |
| # ์นดํ ๊ณ ๋ฆฌ๋ณ ํ๊ท ์งํ | |
| category_performance = df_merged.groupby('category').agg({ | |
| 'views_total': 'mean', | |
| 'likes': 'mean', | |
| 'comments': 'mean', | |
| 'engagement_rate': 'mean' | |
| }).sort_values('views_total', ascending=False) | |
| fig, ax = plt.subplots(figsize=(14, 10)) | |
| category_performance['views_total'].sort_values().plot(kind='barh', ax=ax, color='skyblue') | |
| ax.set_title('์นดํ ๊ณ ๋ฆฌ๋ณ ํ๊ท ์กฐํ์', fontsize=16) | |
| ax.set_xlabel('ํ๊ท ์กฐํ์') | |
| ax.set_ylabel('์นดํ ๊ณ ๋ฆฌ') | |
| plt.tight_layout() | |
| plt.savefig(f'{output_dir}/category_avg_views.png') | |
| plt.close() | |
| print(" - ์นดํ ๊ณ ๋ฆฌ๋ณ ํ๊ท ์กฐํ์ ๋ถ์ ์๋ฃ. (category_avg_views.png ์ ์ฅ)") | |
| # ํ๊ทธ ๋ถ์ ๋ฐ Word Cloud | |
| tags = df_merged['tag'].dropna().str.split(',').explode().str.strip() | |
| top_tags = tags.value_counts().head(50) | |
| wordcloud = WordCloud( | |
| font_path='malgun', | |
| width=1000, | |
| height=600, | |
| background_color='white', | |
| colormap='viridis' | |
| ).generate_from_frequencies(top_tags) | |
| plt.figure(figsize=(15, 9)) | |
| plt.imshow(wordcloud, interpolation='bilinear') | |
| plt.axis('off') | |
| plt.title('์์ 50๊ฐ ํ๊ทธ Word Cloud', fontsize=20) | |
| plt.tight_layout() | |
| plt.savefig(f'{output_dir}/tags_wordcloud.png') | |
| plt.close() | |
| print(" - ํ๊ทธ Word Cloud ์์ฑ ์๋ฃ. (tags_wordcloud.png ์ ์ฅ)") | |
| # ๋ฐํ ์์ผ๋ณ ๊ธฐ์ฌ ์ ๋ฐ ํ๊ท ์กฐํ์ | |
| fig, axes = plt.subplots(1, 2, figsize=(18, 7)) | |
| day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] | |
| sns.countplot(data=df_merged, y='publish_dayofweek', order=day_order, ax=axes[0], palette='pastel') | |
| axes[0].set_title('์์ผ๋ณ ๋ฐํ ๊ธฐ์ฌ ์', fontsize=16) | |
| axes[0].set_xlabel('๊ธฐ์ฌ ์') | |
| axes[0].set_ylabel('์์ผ') | |
| sns.barplot(data=df_merged, y='publish_dayofweek', x='views_total', order=day_order, ax=axes[1], palette='pastel', ci=None) | |
| axes[1].set_title('์์ผ๋ณ ํ๊ท ์กฐํ์', fontsize=16) | |
| axes[1].set_xlabel('ํ๊ท ์กฐํ์') | |
| axes[1].set_ylabel('') | |
| plt.tight_layout() | |
| plt.savefig(f'{output_dir}/dayofweek_performance.png') | |
| plt.close() | |
| print(" - ๋ฐํ ์์ผ๋ณ ์ฑ๊ณผ ๋ถ์ ์๋ฃ. (dayofweek_performance.png ์ ์ฅ)") | |
| def analyze_demographics(df_demo, df_merged, output_dir): | |
| """์ธ๊ตฌํต๊ณํ์ ํน์ฑ(์ฐ๋ น/์ฑ๋ณ)์ ๋ฐ๋ฅธ ์ฝํ ์ธ ์๋น ํจํด ๋ถ์""" | |
| print("\n[๋จ๊ณ 4] ์ธ๊ตฌํต๊ณ ๊ทธ๋ฃน๋ณ ์ ํธ๋ ๋ถ์...") | |
| # ๊ธฐ์ฌ ID๋ฅผ ๊ธฐ์ค์ผ๋ก ์ธ๊ตฌํต๊ณ ๋ฐ์ดํฐ์ ์ฝํ ์ธ ๋ฐ์ดํฐ ๋ณํฉ | |
| df_demo_content = pd.merge(df_demo, df_merged[['article_id', 'category']], on='article_id', how='left') | |
| # ์ฐ๋ น๋ ๋ฐ ์ฑ๋ณ์ ๋ฐ๋ฅธ ์นดํ ๊ณ ๋ฆฌ๋ณ ์กฐํ์ ์ง๊ณ | |
| demo_category_views = df_demo_content.groupby(['age_group', 'gender', 'category'])['views'].sum().reset_index() | |
| # ํํธ๋งต ์์ฑ์ ์ํ ํผ๋ฒ ํ ์ด๋ธ | |
| # ์ฌ์ฑ ๋ ์ | |
| female_pivot = demo_category_views[demo_category_views['gender'] == '์ฌ'].pivot_table( | |
| index='category', columns='age_group', values='views', aggfunc='sum' | |
| ).fillna(0) | |
| # ๋จ์ฑ ๋ ์ | |
| male_pivot = demo_category_views[demo_category_views['gender'] == '๋จ'].pivot_table( | |
| index='category', columns='age_group', values='views', aggfunc='sum' | |
| ).fillna(0) | |
| # ์๊ฐํ | |
| fig, axes = plt.subplots(2, 1, figsize=(20, 24)) | |
| sns.heatmap(female_pivot, cmap='Reds', annot=True, fmt='.0f', linewidths=.5, ax=axes[0]) | |
| axes[0].set_title('์ฌ์ฑ ์ฐ๋ น๋๋ณ ์ ํธ ์นดํ ๊ณ ๋ฆฌ (์ด ์กฐํ์ ๊ธฐ์ค)', fontsize=18) | |
| axes[0].set_xlabel('์ฐ๋ น๋') | |
| axes[0].set_ylabel('์นดํ ๊ณ ๋ฆฌ') | |
| sns.heatmap(male_pivot, cmap='Blues', annot=True, fmt='.0f', linewidths=.5, ax=axes[1]) | |
| axes[1].set_title('๋จ์ฑ ์ฐ๋ น๋๋ณ ์ ํธ ์นดํ ๊ณ ๋ฆฌ (์ด ์กฐํ์ ๊ธฐ์ค)', fontsize=18) | |
| axes[1].set_xlabel('์ฐ๋ น๋') | |
| axes[1].set_ylabel('์นดํ ๊ณ ๋ฆฌ') | |
| plt.tight_layout() | |
| plt.savefig(f'{output_dir}/demographic_category_preference_heatmap.png') | |
| plt.close() | |
| print(" - ์ธ๊ตฌํต๊ณ ๊ทธ๋ฃน๋ณ ์ ํธ ์นดํ ๊ณ ๋ฆฌ ํํธ๋งต ๋ถ์ ์๋ฃ. (demographic_category_preference_heatmap.png ์ ์ฅ)") | |
| def analyze_referrer(df_referrer, df_merged, output_dir): | |
| """์ ์ ๊ฒฝ๋ก๋ณ ๊ธฐ์ฌ๋ ๋ฐ ํจ์จ์ฑ ๋ถ์""" | |
| print("\n[๋จ๊ณ 5] ์ ์ ๊ฒฝ๋ก๋ณ ํจ์จ์ฑ ๋ถ์...") | |
| # ์ ์ ๊ฒฝ๋ก ๋ฐ์ดํฐ์ ๊ธฐ์ฌ ์งํ ๋ณํฉ | |
| df_referrer_merged = pd.merge(df_referrer, df_merged[['article_id', 'views_total', 'engagement_rate']], on='article_id', how='left') | |
| # ์ฃผ์ ์ ์ ๊ฒฝ๋ก(์์ 10๊ฐ) ์ถ์ถ | |
| top_10_referrers = df_referrer_merged.groupby('referrer')['share'].sum().nlargest(10).index | |
| df_top_referrers = df_referrer_merged[df_referrer_merged['referrer'].isin(top_10_referrers)] | |
| # ์ ์ ๊ฒฝ๋ก๋ณ ํ๊ท ์ฐธ์ฌ๋ ๊ณ์ฐ | |
| referrer_engagement = df_top_referrers.groupby('referrer')['engagement_rate'].mean().sort_values(ascending=False) | |
| fig, axes = plt.subplots(1, 2, figsize=(20, 8)) | |
| # ์ ์ ๊ฒฝ๋ก๋ณ ์ด ๊ธฐ์ฌ๋ | |
| df_top_referrers.groupby('referrer')['share'].sum().sort_values().plot(kind='barh', ax=axes[0], color='c') | |
| axes[0].set_title('์์ 10๊ฐ ์ ์ ๊ฒฝ๋ก๋ณ ์ด ๊ธฐ์ฌ๋(Share)', fontsize=16) | |
| axes[0].set_xlabel('์ด Share') | |
| axes[0].set_ylabel('์ ์ ๊ฒฝ๋ก') | |
| # ์ ์ ๊ฒฝ๋ก๋ณ ํ๊ท ์ฐธ์ฌ๋ | |
| referrer_engagement.sort_values().plot(kind='barh', ax=axes[1], color='m') | |
| axes[1].set_title('์์ 10๊ฐ ์ ์ ๊ฒฝ๋ก๋ณ ํ๊ท ์ฐธ์ฌ๋(%)', fontsize=16) | |
| axes[1].set_xlabel('ํ๊ท ์ฐธ์ฌ๋ (%)') | |
| axes[1].set_ylabel('') | |
| plt.tight_layout() | |
| plt.savefig(f'{output_dir}/referrer_performance.png') | |
| plt.close() | |
| print(" - ์ฃผ์ ์ ์ ๊ฒฝ๋ก๋ณ ๊ธฐ์ฌ๋ ๋ฐ ์ฐธ์ฌ๋ ๋ถ์ ์๋ฃ. (referrer_performance.png ์ ์ฅ)") | |
| # 5. ์ข ํฉ ์ธ์ฌ์ดํธ ์์ฑ | |
| def generate_insights_report(data, output_dir): | |
| """๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ์ผ๋ก ์ข ํฉ์ ์ธ ์ธ์ฌ์ดํธ ๋ณด๊ณ ์๋ฅผ ์์ฑํฉ๋๋ค.""" | |
| print("\n[๋จ๊ณ 6] ์ข ํฉ ์ธ์ฌ์ดํธ ๋ณด๊ณ ์ ์์ฑ...") | |
| # ๋ณด๊ณ ์ ๋ด์ฉ ์์ฑ | |
| report = f""" | |
| # ์ ๋ฌธ๊ณผ๋ฐฉ์ก ๋ ์ ๋ฐ์ดํฐ ์ฌ์ธต ๋ถ์ ๋ณด๊ณ ์ | |
| ์์ฑ์ผ: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} | |
| ## 1. ๋ถ์ ๊ฐ์ | |
| - ๋ณธ ๋ณด๊ณ ์๋ ๊ธฐ์ฌ ์ฑ๊ณผ ์งํ, ์ฝํ ์ธ ํน์ฑ, ๋ ์ ์ธ๊ตฌํต๊ณ, ์ ์ ๊ฒฝ๋ก ๋ฐ์ดํฐ๋ฅผ ์ข ํฉํ์ฌ ๋ ์ ํ๋ ํจํด์ ๋ถ์ํ๊ณ , ์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฝํ ์ธ ์ ๋ต ๊ฐ์ ๋ฐฉ์์ ์ ์ํ๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค. | |
| - ์ด {data['merged']['article_id'].nunique():,}๊ฐ์ ๊ธฐ์ฌ์ ๊ด๋ จ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ์ต๋๋ค. | |
| ## 2. ์ฃผ์ ๋ถ์ ๊ฒฐ๊ณผ (Key Findings) | |
| ### 2.1. ์ฝํ ์ธ ์ฑ๊ณผ | |
| - **์ฑ๊ณผ ๋ถํฌ**: ๋๋ถ๋ถ์ ๊ธฐ์ฌ๋ ์์์ ์กฐํ์๋ฅผ ๊ธฐ๋กํ๋ฉฐ, ์์์ 'ํํธ ๊ธฐ์ฌ'๊ฐ ์ ์ฒด ์กฐํ์๋ฅผ ๊ฒฌ์ธํ๋ ๋กฑํ ์ผ(Long-tail) ๋ถํฌ๋ฅผ ๋ณด์ ๋๋ค. (metrics_overview.png ์ฐธ๊ณ ) | |
| - **ํต์ฌ ์นดํ ๊ณ ๋ฆฌ**: '๋ฏธ๋์ด ไบบ์ฌ์ด๋', '์์ด๋์ด์ค', '๋ฏธ๋์ดยทAIํธ๋ ๋' ์นดํ ๊ณ ๋ฆฌ๊ฐ ํ๊ท ์กฐํ์ ์ต์์๊ถ์ ์ฐจ์งํ์ต๋๋ค. ์ด๋ค ์นดํ ๊ณ ๋ฆฌ๊ฐ ๋ ์์ ๋์ ๊ด์ฌ์ ์ ๋ํ๋ ํต์ฌ ์ฝํ ์ธ ์์ ์์ฌํฉ๋๋ค. (category_avg_views.png ์ฐธ๊ณ ) | |
| - **์ฃผ์ ํ๊ทธ**: '#์ธ๋ก ', '#๊ธฐ์', '#๋ด์ค', '#๋ฏธ๋์ด', '#์ ๋๋ฆฌ์ฆ' ๋ฑ ์ธ๋ก ๋ณธ์ง๊ณผ ๊ด๋ จ๋ ํค์๋๊ฐ ๊ฐ์ฅ ๋น๋ฒํ๊ฒ ์ฌ์ฉ๋์์ต๋๋ค. '#์ธ๊ณต์ง๋ฅ', '#AI', '#ํ ํฌ' ๋ฑ ๊ธฐ์ ๊ด๋ จ ํ๊ทธ๋ ์์๊ถ์ ์์นํ์ฌ ๊ธฐ์ ํธ๋ ๋์ ๋ํ ๋์ ๊ด์ฌ์ ๋ณด์ฌ์ค๋๋ค. (tags_wordcloud.png ์ฐธ๊ณ ) | |
| ### 2.2. ๋ ์ ํน์ฑ | |
| - **์ฃผ์ ๋ ์์ธต**: 10๋ ํ๋ฐ์์ 30๋ ์ด๋ฐ์ ์ ์ ์ธต์ด ์ฝํ ์ธ ์๋น์ ํต์ฌ ๊ทธ๋ฃน์ ๋๋ค. ํนํ 19-24์ธ ์ฌ์ฑ ๊ทธ๋ฃน์ ํ๋์ด ๋๋๋ฌ์ง๋๋ค. | |
| - **์ฑ๋ณ/์ฐ๋ น๋ณ ์ ํธ๋**: | |
| - **์ฌ์ฑ**: 10๋-20๋ ์ด๋ฐ์ '์ปค๋ฒ์คํ ๋ฆฌ', '๋ฏธ๋์ดํฌ๋ผ'์, 20๋ ํ๋ฐ-30๋๋ '์ทจ์ฌ๊ธฐยท์ ์๊ธฐ', '๋ฏธ๋์ด ไบบ์ฌ์ด๋' ๋ฑ ์ฌ์ธต์ ์ธ ์ฝํ ์ธ ์ ๋์ ๋ฐ์์ ๋ณด์ ๋๋ค. | |
| - **๋จ์ฑ**: 20๋-30๋ ๊ทธ๋ฃน์ด ์ ๋ฐ์ ์ธ ์๋น๋ฅผ ์ฃผ๋ํ๋ฉฐ, ํนํ '์ปค๋ฒ์คํ ๋ฆฌ', '์ง์ค์ ๊ฒ'๊ณผ ๊ฐ์ ์์ฌ/๊ธฐํ ๊ธฐ์ฌ์ ๋ํ ๊ด์ฌ์ด ๋์ต๋๋ค. | |
| - (demographic_category_preference_heatmap.png ์ฐธ๊ณ ) | |
| ### 2.3. ์ ์ ๊ฒฝ๋ก ํจ์จ์ฑ | |
| - **์ฃผ์ ์ ์ ์ฑ๋**: 'Google'๊ณผ '๋ค์ด๋ฒ' ๊ด๋ จ ์ฑ๋(ํตํฉ๊ฒ์, ๋ธ๋ก๊ทธ ๋ฑ)์ด ์ ์ฒด ํธ๋ํฝ์ ์๋์ ์ธ ๋น์ค์ ์ฐจ์งํฉ๋๋ค. ๊ฒ์ ์์ง ์ต์ ํ(SEO)์ ์ค์์ฑ์ด ๋งค์ฐ ํฝ๋๋ค. | |
| - **๊ณ ํ์ง ํธ๋ํฝ**: '๋ค์ด๋ฒ ๋ธ๋ก๊ทธ๊ฒ์'์ ๋์ ํธ๋ํฝ ๊ธฐ์ฌ๋์ ํจ๊ป ์ํธํ ๋ ์ ์ฐธ์ฌ๋๋ฅผ ๋ณด์ฌ์ฃผ๋ ํจ์จ์ ์ธ ์ฑ๋์ ๋๋ค. ๋ฐ๋ฉด, 'Google'์ ๊ฐ์ฅ ๋ง์ ํธ๋ํฝ์ ์ ์ ์ํค์ง๋ง, ํ๊ท ์ฐธ์ฌ๋๋ ์๋์ ์ผ๋ก ๋ฎ์ ๋์ ๋ฒ์์ ์ผ๋ฐ ๋ ์ ์ ์ ์ด ๋ง์ ๊ฒ์ผ๋ก ์ถ์ ๋ฉ๋๋ค. (referrer_performance.png ์ฐธ๊ณ ) | |
| ## 3. ์ ๋ต์ ์ ์ธ (Strategic Recommendations) | |
| 1. **์ฝํ ์ธ ๊ฐ์ธํ ๋ฐ ํ๊ฒํ ๊ฐํ**: | |
| - **ํต์ฌ ๋ ์์ธต(19-34์ธ) ์ง์ค**: ์ด๋ค์ด ์ ํธํ๋ '๋ฏธ๋์ด ไบบ์ฌ์ด๋', '๋ฏธ๋์ดยทAIํธ๋ ๋'์ ๊ฐ์ ์ฌ์ธต ๋ถ์ ๋ฐ ํธ๋ ๋ ๊ด๋ จ ์ฝํ ์ธ ๋ฅผ ๊ฐํํ๊ณ , ๊ด๋ จ ์ ๊ท ๊ธฐํ์ ๋ฐ๊ตดํด์ผ ํฉ๋๋ค. | |
| - **์ ์ฌ ๋ ์์ธต(40๋ ์ด์) ๊ณต๋ต**: 40๋ ์ด์ ๋จ๋ ๊ฐ ๊ณตํต์ ์ผ๋ก ๊ด์ฌ์ ๋ณด์ด๋ '์ง์ค์ ๊ฒ', '๋ฏธ๋์ดํ์ฅ' ์นดํ ๊ณ ๋ฆฌ ์ฝํ ์ธ ๋ฅผ ํ์ฉํ์ฌ ์ด ์ฐ๋ น๋์ ํนํ๋ ์ฃผ์ (์: ๋ฏธ๋์ด ๋ฆฌํฐ๋ฌ์, ๊ฐ์ง๋ด์ค ํ๋ณ)๋ก ํ์ฅํ๋ ์ ๋ต์ ๊ณ ๋ คํ ์ ์์ต๋๋ค. | |
| 2. **๊ฒ์์์ง ์ต์ ํ(SEO) ๊ณ ๋ํ**: | |
| - **์ฝํ ์ธ -ํ๊ทธ ์ฐ๊ณ**: Word Cloud ๋ถ์์์ ๋์ถ๋ '#AI', '#๋์งํธ', '#ํ๋ซํผ' ๋ฑ์ ์ธ๊ธฐ ๊ธฐ์ ํ๊ทธ์ '์ปค๋ฒ์คํ ๋ฆฌ', '์ง์ค์ ๊ฒ'๊ณผ ๊ฐ์ ์ธ๊ธฐ ์นดํ ๊ณ ๋ฆฌ๋ฅผ ์กฐํฉํ ์ฝํ ์ธ ๋ฅผ ๊ธฐํํ์ฌ ๊ฒ์ ๋ ธ์ถ ๊ฐ๋ฅ์ฑ์ ๊ทน๋ํํด์ผ ํฉ๋๋ค. | |
| - **๋ธ๋ก๊ทธ ์ฑ๋ ํ์ฉ**: '๋ค์ด๋ฒ ๋ธ๋ก๊ทธ'๊ฐ ์์ง์ ๋ ์๋ฅผ ์ ์ ์ํค๋ ํต์ฌ ์ฑ๋์์ด ํ์ธ๋์์ต๋๋ค. ์นด๋๋ด์ค๋ ๊ธฐ์ฌ ์์ฝ๋ณธ ๋ฑ ๋ธ๋ก๊ทธ ํ๋ซํผ์ ์ต์ ํ๋ 2์ฐจ ์ฝํ ์ธ ๋ฅผ ์ ์ํ์ฌ ๋ฐฐํฌํ๋ ์ ๋ต์ด ์ ํจํฉ๋๋ค. | |
| 3. **๋ ์ ์ฐธ์ฌ๋ ์ฆ์ง ์ ๋ต**: | |
| - **์ฐธ์ฌ๋ ๋์ ์นดํ ๊ณ ๋ฆฌ ๋ฒค์น๋งํน**: '๊ธ๋ก๋ฒ ๋ฏธ๋์ด ํ์ฅ', '๋ฏธ๋์ด ๋ฆฌ๋ทฐ' ๋ฑ ์ฐธ์ฌ๋๊ฐ ๋์ ์นดํ ๊ณ ๋ฆฌ์ ํ์(์: ์ ๋ฌธ๊ฐ ์ธํฐ๋ทฐ, ํน์ ์ฌ๋ก ์ฌ์ธต ๋ถ์, ๋ช ํํ ์ฃผ์ฅ ์ ์)์ ๋ค๋ฅธ ๊ธฐ์ฌ์ ์ ์ฉํด ๋ณผ ์ ์์ต๋๋ค. | |
| - **์ธํฐ๋ํฐ๋ธ ์์ ๋์ **: ๊ธฐ์ฌ ๋ง๋ฏธ์ ๊ด๋ จ ์ฃผ์ ์ ๋ํ ๋ ์ ์๊ฒฌ์ ๋ฌป๋ ์ง๋ฌธ์ ์ถ๊ฐํ๊ฑฐ๋, ํฌํ ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ๋๊ธ ๋ฐ ์ํธ์์ฉ์ ์ ๋ํ๋ ๋ฐฉ์์ ๊ฒํ ํด์ผ ํฉ๋๋ค. | |
| """ | |
| # ๋ฆฌํฌํธ ํ์ผ๋ก ์ ์ฅ | |
| report_path = f'{output_dir}/comprehensive_analysis_report.txt' | |
| with open(report_path, 'w', encoding='utf-8') as f: | |
| f.write(report) | |
| print(f" - ์ข ํฉ ์ธ์ฌ์ดํธ ๋ณด๊ณ ์ ์์ฑ ์๋ฃ. ({report_path} ์ ์ฅ)") | |
| # 6. ๋ฉ์ธ ์คํ ํจ์ | |
| def main(): | |
| """์คํฌ๋ฆฝํธ์ ๋ฉ์ธ ์คํ ๋ก์ง""" | |
| print("===== ์ ๋ฌธ๊ณผ๋ฐฉ์ก ๋ ์ ๋ฐ์ดํฐ ์ฌ์ธต ๋ถ์ ์คํฌ๋ฆฝํธ ์คํ =====") | |
| # 1. ํ๊ฒฝ ์ค์ | |
| data_dir, output_dir = setup_environment() | |
| # 2. ๋ฐ์ดํฐ ๋ก๋ ๋ฐ ์ ์ฒ๋ฆฌ | |
| all_data = load_and_preprocess_data(data_dir) | |
| # 3. ์์ธ ๋ถ์ ๋ฐ ์๊ฐํ ์คํ | |
| analyze_metrics_overview(all_data['merged'], output_dir) | |
| analyze_content_features(all_data['merged'], output_dir) | |
| analyze_demographics(all_data['demo'], all_data['merged'], output_dir) | |
| analyze_referrer(all_data['referrer'], all_data['merged'], output_dir) | |
| # 4. ์ข ํฉ ์ธ์ฌ์ดํธ ๋ณด๊ณ ์ ์์ฑ | |
| generate_insights_report(all_data, output_dir) | |
| print("\n===== ๋ชจ๋ ๋ถ์์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋์์ต๋๋ค. =====") | |
| print(f"๊ฒฐ๊ณผ๋ฌผ์ '{output_dir}' ํด๋์์ ํ์ธํ์ค ์ ์์ต๋๋ค.") | |
| if __name__ == '__main__': | |
| main() |