26J29f3

Young-Kyoo Kim·2026년 6월 29일
"""
[신규 3단계] FinOps 다차원 분석 시각화 엔진 (노드분포 + 일자추이 + 요일패턴 매트릭스 통합)
실행: python step3_analytics.py
"""

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from pathlib import Path

MERGED_DIR = Path("./data/merged")
OUT_PLOT_DIR = Path("./data/output/plots")
OUT_PLOT_DIR.mkdir(parents=True, exist_ok=True)

def init_chart_theme():
    plt.rcParams['font.family'] = 'sans-serif'
    plt.rcParams['font.sans-serif'] = ['Arial', 'Helvetica', 'DejaVu Sans']
    plt.rcParams['axes.unicode_minus'] = False 
    sns.set_theme(style="whitegrid")
    plt.rcParams['figure.dpi'] = 130

def generate_all_plots():
    df = pd.read_parquet(MERGED_DIR / "enriched_fixed_7d.parquet")
    
    # ── 📸 차트 1: 1,000노드 대응용 노드 효율 분포도 ──
    df_node = df.groupby("node").agg(
        alloc = ("cpu_allocated_core_hours", "sum"),
        used  = ("cpu_usage_core_hours", "sum")
    ).reset_index()
    df_node["eff_pct"] = (df_node["used"] / df_node["alloc"].clip(lower=0.1) * 100).round(2)
    
    fig, ax = plt.subplots(figsize=(10, 5))
    node_range = df_node["eff_pct"].max() - df_node["eff_pct"].min()
    if node_range == 0 or np.isnan(node_range):
        sns.histplot(data=df_node, x="eff_pct", bins=5, kde=False, color="#1F4E79", ax=ax)
    else:
        sns.histplot(data=df_node, x="eff_pct", binwidth=5, kde=True, color="#1F4E79", ax=ax)
    ax.set_title("Per-Node CPU Efficiency Density Distribution Profiling", weight="bold", pad=15)
    ax.set_xlabel("Node Resource Efficiency Score (%)")
    fig.savefig(OUT_PLOT_DIR / "chart_n2_node_distribution.png", bbox_inches="tight")
    plt.close(fig)

    # ── 📸 차트 2: 일자별 워크로드 낭비량 추이 누적 막대 ──
    df_trend = df.groupby(["date", "workload_type"])["cpu_waste_core_hours"].sum().unstack().fillna(0)
    fig, ax = plt.subplots(figsize=(11, 5.5))
    df_trend.plot(kind="bar", stacked=True, ax=ax, cmap="Set3", edgecolor="gray", linewidth=0.4)
    ax.set_title("Daily CPU Waste Footprint by Workload Technical Domains", weight="bold", pad=15)
    ax.set_ylabel("Total Waste Scale (Core-Hours)")
    plt.xticks(rotation=0)
    plt.legend(bbox_to_anchor=(1.02, 1), loc="upper left")
    fig.savefig(OUT_PLOT_DIR / "chart_t2_daily_waste_stack.png", bbox_inches="tight")
    plt.close(fig)

    # ── 📸 차트 3: 워크로드 × 요일(날짜) 자원 패턴 매트릭스 히트맵 ──
    fig, ax = plt.subplots(figsize=(11, 5.5))
    sns.heatmap(df_trend, annot=True, fmt=",.1f", cmap="YlOrRd", linewidths=0.5, linecolor="gray", ax=ax, annot_kws={"weight": "bold", "size": 9})
    ax.set_title("Infrastructure 2-Dimensional Resource Waste Pattern Matrix", weight="bold", pad=15)
    ax.set_xlabel("Observation Dates")
    ax.set_ylabel("Workload Domains")
    fig.savefig(OUT_PLOT_DIR / "chart_p1_waste_heatmap.png", bbox_inches="tight")
    plt.close(fig)
    
    print("✅ [시각화 완료] 3대 마스터 인프라 분석 차트 이미지 저장 완수.")

if __name__ == "__main__":
    init_chart_theme()
    generate_all_plots()

0개의 댓글